diff --git a/.classpath b/.classpath deleted file mode 100644 index e01fe513..00000000 --- a/.classpath +++ /dev/null @@ -1,44 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 00000000..b5e6a76d --- /dev/null +++ b/.gitattributes @@ -0,0 +1,5 @@ +# Github language stats file +external/* linguist-vendored +lib/* linguist-vendored +*.css linguist-vendored +*.js linguist-vendored \ No newline at end of file diff --git a/.gitignore b/.gitignore old mode 100755 new mode 100644 index 47284c32..cc2fb2a5 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,14 @@ -/screenlog.0* +# Configuration and dependencies /hal.conf /hal.db* -/build/ -/lib/Zutil.jar +/lib/zutil-* +/recordings/ + +# Runtime files +/screenlog.0* +/OZW_Log.txt + +# Build and Ide files +build +.gradle +.idea \ No newline at end of file diff --git a/.project b/.project deleted file mode 100644 index 2656b0ff..00000000 --- a/.project +++ /dev/null @@ -1,17 +0,0 @@ - - - hal - - - - - - org.eclipse.jdt.core.javabuilder - - - - - - org.eclipse.jdt.core.javanature - - diff --git a/Hal.iml b/Hal.iml deleted file mode 100755 index 5f300ff3..00000000 --- a/Hal.iml +++ /dev/null @@ -1,40 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/Jenkinsfile b/Jenkinsfile new file mode 100644 index 00000000..c82929e5 --- /dev/null +++ b/Jenkinsfile @@ -0,0 +1,35 @@ +// Jenkinsfile (Pipeline Script) +node { + // Configure environment + env.JAVA_HOME = tool name: 'jdk-11' + env.REPO_URL = "repo.koc.se/hal.git" //scm.getUserRemoteConfigs()[0].getUrl() + env.BUILD_NAME = "BUILD-${env.BUILD_ID}" + + + checkout scm + + stage('Build') { + sh './gradlew clean' + sh './gradlew build' + } + + stage('Test') { + try { + sh './gradlew test' + } finally { + junit testResults: '**/build/test-results/test/*.xml' + } + } + + stage('Package') { + sh './gradlew distZip' + archiveArtifacts artifacts: 'build/distributions/Hal.zip', fingerprint: true + + // Tag artifact + withCredentials([[$class: 'UsernamePasswordMultiBinding', credentialsId: 'f8e5f6c6-4adb-4ab2-bb5d-1c8535dff491', + usernameVariable: 'USERNAME', passwordVariable: 'PASSWORD']]) { + sh "git tag ${env.BUILD_NAME}" + sh "git push 'https://${USERNAME}:${PASSWORD}@${env.REPO_URL}' ${env.BUILD_NAME}" + } + } +} diff --git a/LICENSE.txt b/LICENSE.txt old mode 100755 new mode 100644 diff --git a/README.md b/README.md old mode 100755 new mode 100644 index 4e797208..5a054d6b --- a/README.md +++ b/README.md @@ -1,39 +1,56 @@ # Hal Hal is a home automation hub with sensor statistics with the functionality to -share that data between friends. It is developed to be very extensible so future +share that data between friends. It has been developed to be very extensible so future Sensors and other input devices can be supported. - + +Features: +- **Map**, Set up a house map with sensors and events mapped on a floorplan +- **Triggers and Actions**, IFTTT type functionality +- **Power;Challenge**, Sync power or sensor usage between friends to challenge each other to lower the power usage +- **[Google Assistant Integration](plugins/hal-assistant-google/READNME.md)** + Currently supported devices: - **Network Scanner**, IP scanner to detect devices on local network - **NUT**, Linux UPS daemon - **Tellstick**, Supported devices: - - NexaSelfLearning - - Oregon0x1A2D + - NexaSelfLearning + - Oregon0x1A2D - **Raspberry Pi**, GPIO connected sensors +- **[Zigbee](plugins/hal-zigbee/README.md)** + - Temperature Sensors + - Humidity Sensors + - Pressure Sensors + - OnnOff Devices +- **Google Assistant** +- **MQTT Devices** + +Under development (Not ready to be used yet) +- **Z-Wave** -The project is currently in alpha state, and as such things will change and break. +The project is currently in alpha state, and as such things will change and break continuously. ### Screenshots -![](screenshot_01.jpg) +![Week Graph](screenshot_01.jpg) -![](screenshot_02.jpg) +![Home Map](screenshot_02.jpg) -![](screenshot_03.jpg) +![Sensor Overview](screenshot_03.jpg) -![](screenshot_04.jpg) +![Event Overview](screenshot_04.jpg) ## Installing To run the Hal server you first need to clone the git repository and then run the -ant command to build and run: +gradle command to build and run the server: ``` -ant run +./gradlew run ``` -Check `hal.conf.example` for available configuration options. +Check `hal.conf.example` for available configuration options. +By default, HAL server will be listening to http://localhost:8080. ## Running the tests @@ -41,7 +58,34 @@ The current test coverage is greatly lacking, but to run the available JUnit test-cases run: ``` -ant test +./gradlew test +``` + +## Architecture + +``` + HalAbstractControlerManager + | + | HalAbstractController + | | + | | HalAbstractDevice + | | | + .-----------. .------------. .--------. + | | | | | | + | | | | ----> | Device | + | | | | | | + | | ----> | Controller | '--------' + | | | | .--------. + | | | | | | + | Manager | | | ----> | Device | + | | | | | | + | | '------------' '--------' + | | .------------. .--------. + | | | | | | + | | ----> | Controller | ----> | Device | + | | | | | | + '-----------' '------------' '--------' + ``` ## Authors diff --git a/arduino/ArduinoTellstickDuo/archtech.cpp b/arduino/ArduinoTellstickDuo/archtech.cpp index 74662a3b..491ce88d 100644 --- a/arduino/ArduinoTellstickDuo/archtech.cpp +++ b/arduino/ArduinoTellstickDuo/archtech.cpp @@ -59,28 +59,28 @@ bool parseArctechSelfLearning(uint8_t* bufStartP, uint8_t* bufEndP) { //start uint64_t data = 0; bool dimValuePresent; uint8_t b1,b2,b3,b4; - + //parse preamp b1 = *bufStartP; stepBufferPointer(&bufStartP); b2 = *bufStartP; stepBufferPointer(&bufStartP); - if(!IS_PREAMP(b1, b2)){ + if (!IS_PREAMP(b1, b2)){ return false; } //parse data - + uint16_t dataBitsInBuffer = (calculateBufferPointerDistance(bufStartP, bufEndP)-2) / 4; //each bit is representd by 4 high/low if (dataBitsInBuffer == 32) { dimValuePresent = false; - }else if(dataBitsInBuffer == 36){ + } else if (dataBitsInBuffer == 36){ dimValuePresent = true; } else { return false; } - + for (uint8_t i = 0; i < dataBitsInBuffer; ++i) { b1 = *bufStartP; //no of high stepBufferPointer(&bufStartP); @@ -103,7 +103,7 @@ bool parseArctechSelfLearning(uint8_t* bufStartP, uint8_t* bufEndP) { //start } //data parsed - send event over serial - + Serial.print(F("+Wclass:command;protocol:arctech;model:selflearning;data:0x")); uint8_t hexToSend = (dimValuePresent ? 9 : 8); for (int8_t i = hexToSend - 1; i >= 0; --i) { diff --git a/arduino/ArduinoTellstickDuo/rf.cpp b/arduino/ArduinoTellstickDuo/rf.cpp index 0d5a31a7..c97cc0d7 100644 --- a/arduino/ArduinoTellstickDuo/rf.cpp +++ b/arduino/ArduinoTellstickDuo/rf.cpp @@ -17,29 +17,29 @@ void parseRadioRXBuffer() { bool parse = false; while (bufferReadP != bufferWriteP) { //stop if the read pointer is pointing to where the writing is currently performed uint8_t sampleCount = *bufferReadP; - + if ( (((uintptr_t)bufferReadP) & 0x1) == 1 ) { //buffer pointer is odd (stores highs) //Serial.print("high:"); Serial.println(sampleCount); if (prevValue >= SILENCE_LENGTH) { startDataP = bufferReadP; //some new data must start here since this is the first "high" after a silent period } - + //stream data to stream parsers parseOregonStream(HIGH, sampleCount); - + } else { //buffer pointer is even (stores lows) //Serial.print("low:"); Serial.println(sampleCount); if (sampleCount >= SILENCE_LENGTH) { //evaluate if it is time to parse the curernt data endDataP = bufferReadP; //this is a silient period and must be the end of a data - if(startDataP != 0){ + if (startDataP != 0){ parse = true; break; } } - + //stream data to stream parsers parseOregonStream(LOW, sampleCount); - + } //step the read pointer one step @@ -74,11 +74,11 @@ void parseRadioRXBuffer() { //Let all available parsers parse the data set now. parseArctechSelfLearning(startDataP, endDataP); //TODO: add more parsers here - + //reset the data pointers since the data have been parsed at this point startDataP = 0; endDataP = 0; - + }; //end radioTask void sendTCodedData(uint8_t* data, uint8_t T_long, uint8_t* timings, uint8_t repeat, uint8_t pause) { @@ -88,7 +88,7 @@ void sendTCodedData(uint8_t* data, uint8_t T_long, uint8_t* timings, uint8_t rep for (int i = 0; i < T_long; ++i) { uint8_t timeIndex = (data[i / 4] >> (6 - (2 * (i % 4)))) & 0x03; if (timings[timeIndex] > 0 || i == T_long - 1) { - if(nextPinState){ + if (nextPinState){ TX_PIN_HIGH(); }else{ TX_PIN_LOW(); @@ -111,7 +111,7 @@ void sendSCodedData(uint8_t* data, uint8_t pulseCount, uint8_t repeat, uint8_t p bool nextPinState = HIGH; for (int i = 0; i < pulseCount; ++i) { if (data[i] > 0 || i == pulseCount - 1) { - if(nextPinState){ + if (nextPinState){ TX_PIN_HIGH(); }else{ TX_PIN_LOW(); diff --git a/arduino/HalMultiSensor/HalConfiguration.h b/arduino/HalMultiSensor/HalConfiguration.h old mode 100755 new mode 100644 index 374981c5..afab67fa --- a/arduino/HalMultiSensor/HalConfiguration.h +++ b/arduino/HalMultiSensor/HalConfiguration.h @@ -6,24 +6,25 @@ #define TIMER_MILLISECOND 60000 // poling in minutes #define INDICATOR_PIN 13 // diode -#define DEVICE_BASE_ID 20 +#define TX_PIN 11 +#define DEVICE_BASE_ID 99 // POWER CONSUMPTION SENSOR //#define POWERCON_ENABLED // comment out to disable sensor #define POWERCON_SENSOR SensorPhotocell() -#define POWERCON_PROTOCOL ProtocolOregon(11, DEVICE_BASE_ID + 1) +#define POWERCON_PROTOCOL ProtocolOregon(TX_PIN, DEVICE_BASE_ID + 0) #define POWER_TIMER_MULTIPLIER 1 // TEMPERATURE SENSOR #define TEMPERATURE_ENABLED // comment out to disable sensor #define TEMPERATURE_SENSOR SensorDHT(DHT11, 10) -#define TEMPERATURE_PROTOCOL ProtocolOregon(11, DEVICE_BASE_ID + 2) +#define TEMPERATURE_PROTOCOL ProtocolOregon(TX_PIN, DEVICE_BASE_ID + 1) #define TEMPERATURE_TIMER_MULTIPLIER 10 // LIGHT SENSOR -#define LIGHT_ENABLED // comment out to disable sensor +//#define LIGHT_ENABLED // comment out to disable sensor #define LIGHT_SENSOR SensorBH1750() -#define LIGHT_PROTOCOL ProtocolOregon(11, DEVICE_BASE_ID + 3) +#define LIGHT_PROTOCOL ProtocolOregon(TX_PIN, DEVICE_BASE_ID + 2) #define LIGHT_TIMER_MULTIPLIER 10 diff --git a/arduino/HalMultiSensor/HalInclude.h b/arduino/HalMultiSensor/HalInclude.h old mode 100755 new mode 100644 diff --git a/arduino/HalMultiSensor/HalInterfaces.h b/arduino/HalMultiSensor/HalInterfaces.h old mode 100755 new mode 100644 diff --git a/arduino/HalMultiSensor/HalMultiSensor.ino b/arduino/HalMultiSensor/HalMultiSensor.ino old mode 100755 new mode 100644 index c7bc6714..0b9f3b4b --- a/arduino/HalMultiSensor/HalMultiSensor.ino +++ b/arduino/HalMultiSensor/HalMultiSensor.ino @@ -10,6 +10,15 @@ the data to a central location. #include "Interrupt.h" +#ifndef POWERCON_ENABLED + #define POWER_TIMER_MULTIPLIER 1 +#endif +#ifndef TEMPERATURE_ENABLED + #define TEMPERATURE_TIMER_MULTIPLIER 1 +#endif +#ifndef LIGHT_ENABLED + #define LIGHT_TIMER_MULTIPLIER 1 +#endif #define TIMER_MULTIPLIER_MAX \ POWER_TIMER_MULTIPLIER * TEMPERATURE_TIMER_MULTIPLIER * LIGHT_TIMER_MULTIPLIER unsigned int timerMultiplier = 0; @@ -83,7 +92,7 @@ void loop() // Send power consumption #ifdef POWERCON_ENABLED - if(timerMultiplier % POWER_TIMER_MULTIPLIER == 0) + if (timerMultiplier % POWER_TIMER_MULTIPLIER == 0) { static PowerData powerData; powerSensor->read(powerData); // not needed, only here for future use @@ -94,7 +103,7 @@ void loop() // Handle temperature sensor #ifdef TEMPERATURE_ENABLED - if(timerMultiplier % TEMPERATURE_TIMER_MULTIPLIER == 0) + if (timerMultiplier % TEMPERATURE_TIMER_MULTIPLIER == 0) { static TemperatureData tempData; tempSensor->read(tempData); @@ -105,7 +114,7 @@ void loop() // Handle light sensor #ifdef LIGHT_ENABLED - if(timerMultiplier % LIGHT_TIMER_MULTIPLIER == 0) + if (timerMultiplier % LIGHT_TIMER_MULTIPLIER == 0) { static LightData lightData; lightSensor->read(lightData); diff --git a/arduino/HalMultiSensor/HalMultiSensorEnclosure.FCStd b/arduino/HalMultiSensor/HalMultiSensorEnclosure.FCStd old mode 100755 new mode 100644 diff --git a/arduino/HalMultiSensor/HalMultiSensorEnclosure_bottom.stl b/arduino/HalMultiSensor/HalMultiSensorEnclosure_bottom.stl old mode 100755 new mode 100644 diff --git a/arduino/HalMultiSensor/HalMultiSensorEnclosure_top.stl b/arduino/HalMultiSensor/HalMultiSensorEnclosure_top.stl old mode 100755 new mode 100644 diff --git a/arduino/HalMultiSensor/Interrupt.cpp b/arduino/HalMultiSensor/Interrupt.cpp old mode 100755 new mode 100644 index 4389e570..009af7e7 --- a/arduino/HalMultiSensor/Interrupt.cpp +++ b/arduino/HalMultiSensor/Interrupt.cpp @@ -36,13 +36,14 @@ void Interrupt::sleep() sleep_enable(); // enables the sleep bit in the mcucr register // so sleep is possible. just a safety pin - power_adc_disable(); + //power_adc_disable(); //power_spi_disable(); + //power_usart0_disable(); //power_timer0_disable(); //power_timer1_disable(); //power_timer2_disable(); //power_twi_disable(); - //power_all_disable() + //power_all_disable(); while( ! Interrupt::wakeUpNow) { @@ -52,7 +53,7 @@ void Interrupt::sleep() sleep_disable(); // first thing after waking from sleep: // disable sleep... - power_adc_enable(); + //power_adc_enable(); //power_spi_enable(); //power_usart0_enable(); //power_timer0_enable(); diff --git a/arduino/HalMultiSensor/Interrupt.h b/arduino/HalMultiSensor/Interrupt.h old mode 100755 new mode 100644 diff --git a/arduino/HalMultiSensor/ProtocolNexa.cpp b/arduino/HalMultiSensor/ProtocolNexa.cpp old mode 100755 new mode 100644 diff --git a/arduino/HalMultiSensor/ProtocolNexa.h b/arduino/HalMultiSensor/ProtocolNexa.h old mode 100755 new mode 100644 diff --git a/arduino/HalMultiSensor/ProtocolOregon.cpp b/arduino/HalMultiSensor/ProtocolOregon.cpp old mode 100755 new mode 100644 index 04e91ca9..96f04174 --- a/arduino/HalMultiSensor/ProtocolOregon.cpp +++ b/arduino/HalMultiSensor/ProtocolOregon.cpp @@ -83,14 +83,14 @@ inline void ProtocolOregon::setId(byte data[], byte id) */ inline void ProtocolOregon::setBatteryLevel(byte data[], bool level) { - if(!level) data[4] = 0x0C; + if (!level) data[4] = 0x0C; else data[4] = 0x00; } inline void ProtocolOregon::setTemperature(byte data[], float temp) { // Set temperature sign - if(temp < 0) + if (temp < 0) { data[6] = 0x08; temp *= -1; @@ -127,9 +127,9 @@ inline void ProtocolOregon::calculateAndSetChecksum(byte data[]) for(byte i = 0; i<8;i++) { sum += (data[i]&0xF0) >> 4; - sum += (data[i]&0xF); + sum += (data[i]&0x0F); } - data[8] = ((sum - 0xa) & 0xFF); + data[8] = ((sum - 0x0A) & 0xFF); } diff --git a/arduino/HalMultiSensor/ProtocolOregon.h b/arduino/HalMultiSensor/ProtocolOregon.h old mode 100755 new mode 100644 diff --git a/arduino/HalMultiSensor/SensorBH1750.cpp b/arduino/HalMultiSensor/SensorBH1750.cpp old mode 100755 new mode 100644 diff --git a/arduino/HalMultiSensor/SensorBH1750.h b/arduino/HalMultiSensor/SensorBH1750.h old mode 100755 new mode 100644 diff --git a/arduino/HalMultiSensor/SensorDHT.cpp b/arduino/HalMultiSensor/SensorDHT.cpp old mode 100755 new mode 100644 diff --git a/arduino/HalMultiSensor/SensorDHT.h b/arduino/HalMultiSensor/SensorDHT.h old mode 100755 new mode 100644 diff --git a/arduino/HalMultiSensor/SensorPhotocell.cpp b/arduino/HalMultiSensor/SensorPhotocell.cpp old mode 100755 new mode 100644 diff --git a/arduino/HalMultiSensor/SensorPhotocell.h b/arduino/HalMultiSensor/SensorPhotocell.h old mode 100755 new mode 100644 diff --git a/build.gradle b/build.gradle new file mode 100644 index 00000000..5f07163e --- /dev/null +++ b/build.gradle @@ -0,0 +1,86 @@ +plugins { + id 'java' + id 'application' +} + +// ------------------------------------ +// Hal common configuration +// ------------------------------------ + +allprojects { + repositories { + mavenLocal() + mavenCentral() + } +} + +subprojects { + apply plugin: 'java-library' + + dependencies { + //implementation 'se.koc:zutil:1.0.314' + implementation 'se.koc:zutil:1.0.0-SNAPSHOT' + + testImplementation 'junit:junit:4.12' + testImplementation 'org.hamcrest:hamcrest-core:2.2' + } + + sourceSets { + main { + java { + srcDirs 'src' + } + // We do not want the resource folder to be included in the jar file + //resources { + // srcDir 'resource' + //} + } + test { + java { + srcDirs 'test' + } + } + } +} + +// ------------------------------------ +// Hal general configuration +// ------------------------------------ + +dependencies { + project.subprojects.each { subProject -> + runtimeOnly subProject + } +} + +distributions { + distTar.enabled = false + distZip.enabled = false + + main { + contents { + from 'hal.conf.example' + from 'logging.properties' + + from "${buildDir}/resources" + } + } +} + +task copyRecources(type: Copy) { + doFirst{ + System.out.println("Copying resource files...") + } + + project.subprojects.each { subProject -> + from "${subProject.projectDir}/resources" + } + + into("${buildDir}/resources") +} + +processResources.finalizedBy(copyRecources) + +application { + mainClass = 'se.hal.HalServer' +} \ No newline at end of file diff --git a/build.xml b/build.xml deleted file mode 100755 index 6278ccc5..00000000 --- a/build.xml +++ /dev/null @@ -1,138 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/external/Z-Stick_Gen5_Drivers.zip b/external/Z-Stick_Gen5_Drivers.zip new file mode 100644 index 00000000..c5b3356e Binary files /dev/null and b/external/Z-Stick_Gen5_Drivers.zip differ diff --git a/external/marytts-5.1.2/LICENSE.txt b/external/marytts-5.1.2/LICENSE.txt deleted file mode 100755 index 01dc74eb..00000000 --- a/external/marytts-5.1.2/LICENSE.txt +++ /dev/null @@ -1,74 +0,0 @@ -MARY Software User Agreement -11 April 2011 - -MARY is licensed under the following terms. - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU Lesser General Public License as published by -the Free Software Foundation, version 3 of the License. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public License -along with this program. If not, see . - - - - -Applicable Licenses - -MARY is built upon a number of other open source technologies and products. -Here is a list of those products with links to their licenses. - -hts_engine: the HMM-based speech synthesis code in MARY TTS is based on HTS, ported to Java by DFKI. The original HTS can be obtained from -http://hts-engine.sourceforge.net/ -- it is released under the New and -Simplified BSD License. - -freetts: MARY uses code from FreeTTS (http://freetts.sf.net) for various -processing modules and as the source of one method for waveform synthesis. -FreeTTS is licensed under the (BSD-style) FreeTTS license, see -doc/licenses/freetts-license.txt. - -JTok: The JTok tokenizer from http://heartofgold.dfki.de is distributed -under the GNU Lesser General Public License, see http://www.gnu.org or -doc/licenses/LGPL.txt. - -jsresources.jar: A few utility classes from http://www.jsresources.org -are distributed under the terms of the jsresources license, see -doc/licenses/jsresources-license.txt. - -log4j: MARY uses log4j (http://logging.apache.org/log4j) as a logging -mechanism. log4j is distributed under the Apache Software License, see -http://www.apache.org or doc/licenses/apache-software-license.txt - -JUnit: For unit testing of the java source, mary uses JUnit -(http://junit.org). JUnit is licensed under the Common Public License, see -http://junit.org or doc/licenses/CPL.txt. - -java-diff: A java diff implementation from http://www.incava.org/projects/java-diff for input-output-comparisons in the -Mary Expert Interface. java-diff is licensed under the GNU Lesser General -Public License, see http://www.gnu.org or doc/licenses/LGPL.txt. - -fast-md5: A fast md5 checksum implementation from http://www.twmacinta.com/myjava/fast_md5.php -used for computing checksums after downloading voices. fast-md5 is licensed under -the GNU Lesser General Public License, see http://www.gnu.org or doc/licenses/LGPL.txt. - -JavaOpenAIR: MARY can optionally be used as an OpenAIR component, -building on the JavaOpenAIR reference implementation from -http://www.mindmakers.org, which is licensed under the -(BSD-style) JavaOpenAIR license, see doc/licenses/JavaOpenAIR-license.txt -(files concerned: JavaOpenAIR.jar) - -mwdumper: A tool for extracting sets of pages from a MediaWiki dump file. -mwdumper is MIT-style like licensed, see http://www.mediawiki.org/wiki/Mwdumper -and for the license http://en.wikipedia.org/wiki/MIT_License. -(files concerned: mwdumper-2008-04-13.jar) - - -sgt: The Scientific Graphics Toolkit (sgt) is provided by the NOAA/PMEL/EPIC group (see http://www.epic.noaa.gov/java/sgt/) under the BSD-style EPIC license, see doc/licenses/epic-license.txt. - -IT IS YOUR OBLIGATION TO READ AND ACCEPT ALL SUCH TERMS -AND CONDITIONS PRIOR TO USE OF THIS CONTENT. diff --git a/external/marytts-5.1.2/bin/marytts-client b/external/marytts-5.1.2/bin/marytts-client deleted file mode 100755 index f20b9315..00000000 --- a/external/marytts-5.1.2/bin/marytts-client +++ /dev/null @@ -1,10 +0,0 @@ -#!/bin/bash -########################################################################## -# MARY TTS client -########################################################################## - -# Set the Mary base installation directory in an environment variable: -BINDIR="`dirname "$0"`" -export MARY_BASE="`(cd "$BINDIR"/.. ; pwd)`" - -java -showversion -ea -Dserver.host=localhost -Dserver.port=59125 -jar "$MARY_BASE/lib/marytts-client-5.1.2-jar-with-dependencies.jar" diff --git a/external/marytts-5.1.2/bin/marytts-client.bat b/external/marytts-5.1.2/bin/marytts-client.bat deleted file mode 100755 index 4a231d9f..00000000 --- a/external/marytts-5.1.2/bin/marytts-client.bat +++ /dev/null @@ -1,10 +0,0 @@ -@echo off -set BINDIR=%~dp0 -call :RESOLVE "%BINDIR%\.." MARY_BASE - -java -showversion -ea -Dserver.host=localhost -Dserver.port=59125 -jar "%MARY_BASE%\lib\marytts-client-5.1.2-jar-with-dependencies.jar" -goto :EOF - -:RESOLVE -set %2=%~f1 -goto :EOF diff --git a/external/marytts-5.1.2/bin/marytts-component-installer b/external/marytts-5.1.2/bin/marytts-component-installer deleted file mode 100755 index 44cea75d..00000000 --- a/external/marytts-5.1.2/bin/marytts-component-installer +++ /dev/null @@ -1,5 +0,0 @@ -#!/bin/sh -BINDIR="`dirname "$0"`" -export MARY_BASE="`(cd "$BINDIR"/.. ; pwd)`" -java -showversion -ea -Dmary.base="$MARY_BASE" $* -cp "$MARY_BASE/lib/*" marytts.tools.install.InstallerGUI - diff --git a/external/marytts-5.1.2/bin/marytts-component-installer.bat b/external/marytts-5.1.2/bin/marytts-component-installer.bat deleted file mode 100755 index 8f4ff657..00000000 --- a/external/marytts-5.1.2/bin/marytts-component-installer.bat +++ /dev/null @@ -1,9 +0,0 @@ -@echo off -set BINDIR=%~dp0 -call :RESOLVE "%BINDIR%\.." MARY_BASE -java -showversion -ea -Dmary.base="%MARY_BASE%" -cp ".;%MARY_BASE%\lib\*" marytts.tools.install.InstallerGUI -goto :EOF - -:RESOLVE -set %2=%~f1 -goto :EOF diff --git a/external/marytts-5.1.2/bin/marytts-server b/external/marytts-5.1.2/bin/marytts-server deleted file mode 100755 index be3c0939..00000000 --- a/external/marytts-5.1.2/bin/marytts-server +++ /dev/null @@ -1,11 +0,0 @@ -#!/bin/bash -########################################################################## -# MARY TTS server -########################################################################## - -# Set the Mary base installation directory in an environment variable: -BINDIR="`dirname "$0"`" -export MARY_BASE="`(cd "$BINDIR"/.. ; pwd)`" - - -java -showversion -ea -Xms40m -Xmx1g -cp "$MARY_BASE/lib/*" -Dmary.base="$MARY_BASE" $* marytts.server.Mary diff --git a/external/marytts-5.1.2/bin/marytts-server.bat b/external/marytts-5.1.2/bin/marytts-server.bat deleted file mode 100755 index f3cc2dad..00000000 --- a/external/marytts-5.1.2/bin/marytts-server.bat +++ /dev/null @@ -1,14 +0,0 @@ -@echo off - -rem Set the Mary base installation directory in an environment variable: -set BINDIR=%~dp0 - -call :RESOLVE "%BINDIR%\.." MARY_BASE - -set CLASSPATH=".;%MARY_BASE%\lib\*" -java -showversion -ea -Xms40m -Xmx1g -cp %CLASSPATH% "-Dmary.base=%MARY_BASE%" marytts.server.Mary -goto :EOF - -:RESOLVE -set %2=%~f1 -goto :EOF diff --git a/external/marytts-5.1.2/doc/examples/client/MaryClient.py b/external/marytts-5.1.2/doc/examples/client/MaryClient.py deleted file mode 100755 index 46569873..00000000 --- a/external/marytts-5.1.2/doc/examples/client/MaryClient.py +++ /dev/null @@ -1,367 +0,0 @@ -#!/usr/bin/python -# -*- coding: utf-8 -*- -import socket, sys, types, getopt - - -languageNames = {'de':'German', - 'en':'English', - 'en_US':'US English', - 'tib':'Tibetan'} - -class MaryClient: - specificationVersion = "0.1" - - """Python implementation of a MARY TTS client""" - def __init__( self, host="cling.dfki.uni-sb.de", port=59125, profile=False, quiet=False ): - self.host = host - self.port = port - self.profile = profile - self.quiet = quiet - self.allVoices = None # array of Voice objects - self.voicesByLocaleMap = {} # Map locale strings to arrays of Voice objects - self.allDataTypes = None # array of DataType objects - self.inputDataTypes = None # array of DataType objects - self.outputDataTypes = None # array of DataType objects - self.serverExampleTexts = {} - self.voiceExampleTexts = {} - self.serverVersionInfo = u'' - - if not self.quiet: - sys.stderr.write( "MARY TTS Python Client %s\n" % ( self.specificationVersion ) ) - try: - info = self.getServerVersionInfo() - except: - sys.stderr.write( "Problem connecting to mary server at %s:%i\n" % ( self.host, self.port ) ) - raise - sys.stderr.write( "Connected to %s:%i, " % ( self.host, self.port ) ) - sys.stderr.write( info ) - sys.stderr.write( '\n' ) - - def __getServerInfo( self, request="", marySocket=None ): - """Get answer to request from mary server. Returns a list of unicode strings, - each representing a line without the line break. - """ - closeSocket = False - if marySocket is None: - closeSocket = True - marySocket = socket.socket( socket.AF_INET, socket.SOCK_STREAM ) - marySocket.connect( ( self.host, self.port ) ) - assert isinstance(marySocket, socket.SocketType) - maryFile = marySocket.makefile( 'rwb', 1 ) # read-write, line-buffered - maryFile.write( unicode( request+"\n" ).encode( 'utf-8' ) ) - result = [] - while True: - got = unicode( maryFile.readline().strip(), 'utf-8' ) - # read until end of file or an empty line is read: - if not got: break - result.append(got) - if closeSocket: - marySocket.close() - return result - - def getServerVersionInfo( self ): - "Get version info from server. Returns a unicode string" - if self.serverVersionInfo == u'': - # need to get it from server - self.serverVersionInfo = u'\n'.join(self.__getServerInfo("MARY VERSION")) - return self.serverVersionInfo - - def getAllDataTypes(self, locale=None): - """Obtain a list of all data types known to the server. If the information is not - yet available, the server is queried. This is optional information - which is not required for the normal operation of the client, but - may help to avoid incompatibilities. - Returns an array of DataType objects - """ - if self.allDataTypes is None: - self.__fillDataTypes() - assert self.allDataTypes is not None and len( self.allDataTypes ) > 0 - if locale is None: - return self.allDataTypes - else: - assert isinstance(locale, types.UnicodeType), "Unexpected type for locale: '%s'" % (type(locale)) - return [d for d in self.allDataTypes if d.locale is None or d.locale == locale] - - def getInputDataTypes(self,locale=None): - """Obtain a list of input data types known to the server. If the information is not - yet available, the server is queried. This is optional information - which is not required for the normal operation of the client, but - may help to avoid incompatibilities. - Returns an arry of DataType objects - """ - if self.inputDataTypes is None: - self.__fillDataTypes() - assert self.inputDataTypes is not None and len( self.inputDataTypes ) > 0 - if locale is None: - return self.inputDataTypes - else: - assert isinstance(locale, types.UnicodeType), "Unexpected type for locale: '%s'" % (type(locale)) - return [d for d in self.inputDataTypes if d.locale is None or d.locale == locale] - - def getOutputDataTypes(self, locale=None): - """Obtain a list of output data types known to the server. If the information is not - yet available, the server is queried. This is optional information - which is not required for the normal operation of the client, but - may help to avoid incompatibilities. - Returns an arry of DataType objects - """ - if self.outputDataTypes is None: - self.__fillDataTypes() - assert self.outputDataTypes is not None and len( self.outputDataTypes ) > 0 - if locale is None: - return self.outputDataTypes - else: - assert isinstance(locale, types.UnicodeType), "Unexpected type for locale: '%s'" % (type(locale)) - return [d for d in self.outputDataTypes if d.locale is None or d.locale == locale] - - - def __fillDataTypes( self ): - self.allDataTypes = [] - self.inputDataTypes = [] - self.outputDataTypes = [] - marySocket = socket.socket( socket.AF_INET, socket.SOCK_STREAM ) - marySocket.connect( ( self.host, self.port ) ) - # Expect a variable number of lines of the kind - # RAWMARYXML INPUT OUTPUT - # TEXT_DE LOCALE=de INPUT - # AUDIO OUTPUT - typeStrings = self.__getServerInfo( "MARY LIST DATATYPES", marySocket ) - if not typeStrings or len(typeStrings) == 0: - raise IOError( "Could not get list of data types from Mary server" ) - marySocket.close() - for typeString in typeStrings: - parts = typeString.split() - if len( parts ) == 0: - continue - name = parts[0] - isInputType = False - isOutputType = False - locale = None - for part in parts[1:]: - if part[:7] == "LOCALE=": - locale = part[7:] - elif part == "INPUT": - isInputType = True - elif part == "OUTPUT": - isOutputType = True - dt = DataType( name, locale, isInputType, isOutputType ) - self.allDataTypes.append( dt ) - if dt.isInputType: - self.inputDataTypes.append( dt ) - if dt.isOutputType: - self.outputDataTypes.append( dt ) - - def getVoices( self, locale=None ): - """Obtain a list of voices known to the server. If the information is not - yet available, the server is queried. This is optional information - which is not required for the normal operation of the client, but - may help to avoid incompatibilities. - Returns an array of Voice objects - """ - if self.allVoices is None: - self.__fillVoices() - assert self.allVoices is not None and len( self.allVoices ) > 0 - if locale is None: - return self.allVoices - else: - assert isinstance(locale, types.UnicodeType), "Unexpected type for locale: '%s'" % (type(locale)) - if self.voicesByLocaleMap.has_key(locale): - return self.voicesByLocaleMap[locale] - else: - raise Exception("No voices for locale '%s'" % (locale)) - - def __fillVoices( self ): - self.allVoices = [] - self.voicesByLocaleMap = {} - marySocket = socket.socket( socket.AF_INET, socket.SOCK_STREAM ) - marySocket.connect( ( self.host, self.port ) ) - # Expect a variable number of lines of the kind - # de7 de female - # us2 en male - # dfki-stadium-emo de male limited - voiceStrings = self.__getServerInfo( "MARY LIST VOICES", marySocket ) - if not voiceStrings or len(voiceStrings) == 0: - raise IOError( "Could not get list of voices from Mary server" ) - marySocket.close() - for voiceString in voiceStrings: - parts = voiceString.split() - if len( parts ) < 3: - continue - name = parts[0] - locale = parts[1] - gender = parts[2] - domain = None - if len( parts ) > 3: - domain = parts[3] - voice = Voice( name, locale, gender, domain ) - self.allVoices.append( voice ) - localeVoices = None - if self.voicesByLocaleMap.has_key( locale ): - localeVoices = self.voicesByLocaleMap[locale] - else: - localeVoices = [] - self.voicesByLocaleMap[locale] = localeVoices - localeVoices.append( voice ) - - def getGeneralDomainVoices( self, locale=None ): - """Obtain a list of general domain voices known to the server. If the information is not - yet available, the server is queried. This is optional information - which is not required for the normal operation of the client, but - may help to avoid incompatibilities. - Returns an array of Voice objects - """ - return [v for v in self.getVoices( locale ) if not v.isLimitedDomain] - - def getLimitedDomainVoices( self, locale=None ): - """Obtain a list of limited domain voices known to the server. If the information is not - yet available, the server is queried. This is optional information - which is not required for the normal operation of the client, but - may help to avoid incompatibilities. - Returns an array of Voice objects - """ - return [v for v in self.getVoices( locale ) if v.isLimitedDomain] - - def getAvailableLanguages(self): - """ Check available voices and return a list of tuples (abbrev, name) - representing the available languages -- e.g. [('en', 'English'),('de', 'German')]. - """ - if self.allVoices is None: - self.__fillVoices() - assert self.allVoices is not None and len( self.allVoices ) > 0 - languages = [] - for l in self.voicesByLocaleMap.keys(): - if languageNames.has_key(l): - languages.append((l,languageNames[l])) - else: - languages.append((l, l)) - return languages - - def getServerExampleText( self, dataType ): - """Request an example text for a given data type from the server. - dataType the string representation of the data type, - e.g. "RAWMARYXML". This is optional information - which is not required for the normal operation of the client, but - may help to avoid incompatibilities.""" - if not self.serverExampleTexts.has_key( dataType ): - exampleTexts = self.__getServerInfo( "MARY EXAMPLETEXT %s" % ( dataType ) ) - if not exampleTexts or len(exampleTexts) == 0: - raise IOError( "Could not get example text for type '%s' from Mary server" % (dataType)) - exampleText = u'\n'.join(exampleTexts) - self.serverExampleTexts[dataType] = exampleText - return self.serverExampleTexts[dataType] - - def process( self, input, inputType, outputType, audioType=None, defaultVoiceName=None, output=sys.stdout ): - assert type( input ) in types.StringTypes - assert type( inputType ) in types.StringTypes - assert type( outputType ) in types.StringTypes - assert audioType is None or type( audioType ) in types.StringTypes - assert defaultVoiceName is None or type( defaultVoiceName ) in types.StringTypes - assert callable( getattr( output, 'write' ) ) - if type( input ) != types.UnicodeType: - input = unicode( input, 'utf-8' ) - maryInfoSocket = socket.socket( socket.AF_INET, socket.SOCK_STREAM ) - maryInfoSocket.connect( ( self.host, self.port ) ) - assert type( maryInfoSocket ) is socket.SocketType - maryInfo = maryInfoSocket.makefile( 'rwb', 1 ) # read-write, line-buffered - maryInfo.write( unicode( "MARY IN=%s OUT=%s" % ( inputType, outputType ), 'utf-8' ) ) - if audioType: - maryInfo.write( unicode( " AUDIO=%s" % ( audioType ), 'utf-8' ) ) - if defaultVoiceName: - maryInfo.write( unicode( " VOICE=%s" % ( defaultVoiceName ), 'utf-8' ) ) - maryInfo.write( "\r\n" ) - # Receive a request ID: - id = maryInfo.readline() - maryDataSocket = socket.socket( socket.AF_INET, socket.SOCK_STREAM ) - maryDataSocket.connect( ( self.host, self.port ) ) - assert type( maryDataSocket ) is socket.SocketType - maryDataSocket.sendall( id ) # includes newline - maryDataSocket.sendall( input.encode( 'utf-8' ) ) - maryDataSocket.shutdown( 1 ) # shutdown writing - # Set mary info socket to non-blocking, so we only read somthing - # if there is something to read: - maryInfoSocket.setblocking( 0 ) - while True: - try: - err = maryInfoSocket.recv( 8192 ) - if err: sys.stderr.write( err ) - except: - pass - got = maryDataSocket.recv( 8192 ) - if not got: break - output.write( got ) - maryInfoSocket.setblocking( 1 ) - while True: - err = maryInfoSocket.recv( 8192 ) - if not err: break - sys.stderr.write( err ) - - - -################ data representation classes ################## - -class DataType: - def __init__( self, name, locale=None, isInputType=False, isOutputType=False ): - self.name = name - self.locale = locale - self.isInputType = isInputType - self.isOutputType = isOutputType - - def isTextType( self ): - return self.name != "AUDIO" - -class Voice: - - def __init__( self, name, locale, gender, domain="general" ): - self.name = name - self.locale = locale - self.gender = gender - self.domain = domain - if not domain or domain == "general": - self.isLimitedDomain = False - else: - self.isLimitedDomain = True - - def __str__(self): - if languageNames.has_key(self.locale): - langName = languageNames[self.locale] - else: - langName = self.locale - if self.isLimitedDomain: - return "%s (%s, %s %s)" % (self.name, self.domain, langName, self.gender) - else: - return "%s (%s %s)" % (self.name, langName, self.gender) - -##################### Main ######################### - -if __name__ == '__main__': - - serverHost = "cling.dfki.uni-sb.de" - serverPort = 59125 - inputType = "TEXT" - outputType = "AUDIO" - audioType = "WAVE" - defaultVoice = None - inputEncoding = 'utf-8' - ( options, rest ) = getopt.getopt( sys.argv[1:], '', \ - ['server.host=', 'server.port=', 'input.type=', 'output.type=', \ - 'audio.type=', 'voice.default=', 'input.encoding='] ) - for ( option, value ) in options: - if option == '--server.host': serverHost = value - elif option == '--server.port': serverPort = int( value ) - elif option == '--input.type': inputType = value - elif option == '--output.type': outputType = value - elif option == '--audio.type': audioType = value - elif option == '--voice.default': defaultVoice = value - elif option == '--input.encoding': inputEncoding = value - if len( rest )>0: # have input file - inputFile = file( rest[0] ) - else: - inputFile = sys.stdin - input = unicode( ''.join( inputFile.readlines() ), inputEncoding ) - if len( rest )>1: # also have output file - outputFile = file( rest[1] ) - else: - outputFile = sys.stdout - - maryClient = MaryClient( serverHost, serverPort ) - maryClient.process( input, inputType, outputType, audioType, defaultVoice, outputFile ) diff --git a/external/marytts-5.1.2/doc/examples/client/MaryClientUser.java b/external/marytts-5.1.2/doc/examples/client/MaryClientUser.java deleted file mode 100755 index a416ab3a..00000000 --- a/external/marytts-5.1.2/doc/examples/client/MaryClientUser.java +++ /dev/null @@ -1,96 +0,0 @@ -/** - * Copyright 2000-2006 DFKI GmbH. - * All Rights Reserved. Use is subject to license terms. - * - * Permission is hereby granted, free of charge, to use and distribute - * this software and its documentation without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of this work, and to - * permit persons to whom this work is furnished to do so, subject to - * the following conditions: - * - * 1. The code must retain the above copyright notice, this list of - * conditions and the following disclaimer. - * 2. Any modifications must be clearly marked as such. - * 3. Original authors' names are not deleted. - * 4. The authors' names are not used to endorse or promote products - * derived from this software without specific prior written - * permission. - * - * DFKI GMBH AND THE CONTRIBUTORS TO THIS WORK DISCLAIM ALL WARRANTIES WITH - * REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL DFKI GMBH NOR THE - * CONTRIBUTORS BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL - * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR - * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS - * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF - * THIS SOFTWARE. - */ - -import marytts.client.MaryClient; -import marytts.util.data.audio.AudioPlayer; -import marytts.util.http.Address; - -import javax.sound.sampled.*; -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.net.UnknownHostException; - -/** - * A demo class illustrating how to use the MaryClient class. - * This will connect to a MARY server, version 4.x. - * It requires maryclient.jar from MARY 4.0. - * This works transparently with MARY servers in both http and socket server mode. - * - * Compile this as follows: - * javac -cp maryclient.jar MaryClientUser.java - * - * And run as: - * java -cp .:maryclient.jar MaryClientUser - * - * @author marc - * - */ - -public class MaryClientUser { - - public static void main(String[] args) - throws IOException, UnknownHostException, UnsupportedAudioFileException, - InterruptedException - { - String serverHost = System.getProperty("server.host", "cling.dfki.uni-sb.de"); - int serverPort = Integer.getInteger("server.port", 59125).intValue(); - MaryClient mary = MaryClient.getMaryClient(new Address(serverHost, serverPort)); - String text = "Willkommen in der Welt der Sprachsynthese!"; - // If the given locale is not supported by the server, it returns - // an ambigous exception: "Problem processing the data." - String locale = "de"; // or US English (en-US), Telugu (te), Turkish (tr), ... - String inputType = "TEXT"; - String outputType = "AUDIO"; - String audioType = "WAVE"; - String defaultVoiceName = null; - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - mary.process(text, inputType, outputType, locale, audioType, defaultVoiceName, baos); - // The byte array constitutes a full wave file, including the headers. - // And now, play the audio data: - AudioInputStream ais = AudioSystem.getAudioInputStream( - new ByteArrayInputStream(baos.toByteArray())); - LineListener lineListener = new LineListener() { - public void update(LineEvent event) { - if (event.getType() == LineEvent.Type.START) { - System.err.println("Audio started playing."); - } else if (event.getType() == LineEvent.Type.STOP) { - System.err.println("Audio stopped playing."); - } else if (event.getType() == LineEvent.Type.OPEN) { - System.err.println("Audio line opened."); - } else if (event.getType() == LineEvent.Type.CLOSE) { - System.err.println("Audio line closed."); - } - } - }; - - AudioPlayer ap = new AudioPlayer(ais, lineListener); - ap.start(); - } -} diff --git a/external/marytts-5.1.2/doc/examples/client/c++/Makefile b/external/marytts-5.1.2/doc/examples/client/c++/Makefile deleted file mode 100755 index a609beda..00000000 --- a/external/marytts-5.1.2/doc/examples/client/c++/Makefile +++ /dev/null @@ -1,45 +0,0 @@ -########################################################################## -# Copyright (C) 2000-2006 DFKI GmbH. -# All rights reserved. Use is subject to license terms. -# -# Permission is hereby granted, free of charge, to use and distribute -# this software and its documentation without restriction, including -# without limitation the rights to use, copy, modify, merge, publish, -# distribute, sublicense, and/or sell copies of this work, and to -# permit persons to whom this work is furnished to do so, subject to -# the following conditions: -# -# 1. The code must retain the above copyright notice, this list of -# conditions and the following disclaimer. -# 2. Any modifications must be clearly marked as such. -# 3. Original authors' names are not deleted. -# 4. The authors' names are not used to endorse or promote products -# derived from this software without specific prior written -# permission. -# -# DFKI GMBH AND THE CONTRIBUTORS TO THIS WORK DISCLAIM ALL WARRANTIES WITH -# REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF -# MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL DFKI GMBH NOR THE -# CONTRIBUTORS BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL -# DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR -# PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS -# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF -# THIS SOFTWARE. -########################################################################## - -CC=g++ -CFLAGS=-Wall -w -O3 -g -ICUDIR=/usr/local/icu -ICULIBS=-Wl,-R,$(ICUDIR)/lib -L$(ICUDIR)/lib -licuuc -licui18n -ldl - -all: MaryDemo - -MaryDemo: MaryClient.o MaryDemo.o - $(CC) $(CFLAGS) *.o -o MaryDemo $(LIBS) - -%.o: %.cc - $(CC) $(CFLAGS) $(RFLAGS) -o $@ -c $< - -clean: - rm -rf *.o ./MaryDemo - diff --git a/external/marytts-5.1.2/doc/examples/client/c++/MaryClient.cc b/external/marytts-5.1.2/doc/examples/client/c++/MaryClient.cc deleted file mode 100755 index 7e920d95..00000000 --- a/external/marytts-5.1.2/doc/examples/client/c++/MaryClient.cc +++ /dev/null @@ -1,277 +0,0 @@ -/** - * Copyright 2000-2006 DFKI GmbH. - * All Rights Reserved. Use is subject to license terms. - * - * Permission is hereby granted, free of charge, to use and distribute - * this software and its documentation without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of this work, and to - * permit persons to whom this work is furnished to do so, subject to - * the following conditions: - * - * 1. The code must retain the above copyright notice, this list of - * conditions and the following disclaimer. - * 2. Any modifications must be clearly marked as such. - * 3. Original authors' names are not deleted. - * 4. The authors' names are not used to endorse or promote products - * derived from this software without specific prior written - * permission. - * - * DFKI GMBH AND THE CONTRIBUTORS TO THIS WORK DISCLAIM ALL WARRANTIES WITH - * REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL DFKI GMBH NOR THE - * CONTRIBUTORS BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL - * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR - * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS - * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF - * THIS SOFTWARE. - */ -#include -#include -#include -#include - -#include "MaryClient.h" - -using namespace std; - -/** - * A C++ implementation of a simple client to the MARY TTS system. - * result: an empty string serving as the container for the output. - * It will return text or audio data; text data will be encoded as UTF-8. - * inputText: the UTF-8 encoded text (or XML document) to send as a request - * maryInFormat: the input type of the data in inputText, e.g. TEXT - * maryOutFormat: the output type to produce, e.g. MBROLA, AUDIO - * locale: the language of the input, e.g. EN-US, DE - * audioType: for AUDIO output, the type of audio data to produce, - * e.g. WAVE or MP3. - * voice: the voice to be used, e.g. cmu-slt-hsmm, bits3. - * effects: the list of effects to be generated. - * return value: 0 on success, negative on failure. - */ -int -MaryClient::maryQuery( int server_port, - string server_host, - string& result, - string inputText, - string maryInFormat, - string maryOutFormat, - string locale, - string audioType, - string voice, - string effects ) { - - // prepare the request - string query = "MARY"; - query += " IN=" + maryInFormat; - query += " OUT=" + maryOutFormat; - query += " LOCALE=" + locale; // remove this line, if using an older version than MARY 4.0 - query += " AUDIO=" + audioType; - query += " VOICE=" + voice; - if (effects != "") { - query += " EFFECTS=" + effects; - } - query += "\012\015"; - - //cout << "Constructed query: " << query << endl; - - // declare connection stuff - struct sockaddr_in maryServer; - struct sockaddr_in maryClient; - struct hostent* hostInfo; - - // declare variables - int maryInfoSocket; - int maryDataSocket; - - // set configuration parameters - - // get host information - hostInfo = gethostbyname (server_host.c_str()); - - if (hostInfo == NULL) - { - return -2; - } - - - // create a tcp connection to the mary server - maryInfoSocket = socket (AF_INET, SOCK_STREAM, 0); - - // verify that the socket could be opened successfully - if (maryInfoSocket == -1) - { - return -2; - } - else - // autoflush stdout, bind and connect - { - maryClient.sin_family = AF_INET; - maryClient.sin_port = htons (0); - maryClient.sin_addr.s_addr = INADDR_ANY; - - int status = bind (maryInfoSocket, (struct sockaddr*) &maryClient, sizeof (maryClient)); - - if (status != 0) - { - return -2; - } - - maryServer.sin_family = AF_INET; - maryServer.sin_port = htons (server_port); - memcpy ((char*) &maryServer.sin_addr.s_addr, hostInfo->h_addr_list [0], hostInfo->h_length); - - status = connect (maryInfoSocket, (struct sockaddr*) &maryServer, sizeof (maryServer)); - - if (status != 0) - { - return -2; - } - } - - // send request to the Mary server - if (send (maryInfoSocket, query.c_str (), query.size (), 0) == -1) - { - return -2; - } - - - // receive the request id - char id [32] = ""; - - if (recv (maryInfoSocket, id, 32, 0) == -1) - { - return -2; - } - - //cout << "Read id: " << id << endl; - - // create a tcp connection to the mary server - maryDataSocket = socket (AF_INET, SOCK_STREAM, 0); - - // verify that the socket could be opened successfully - if (maryDataSocket == -1) - { - return -2; - } - else - // autoflush stdout, bind and connect - { - maryClient.sin_family = AF_INET; - maryClient.sin_port = htons (0); - maryClient.sin_addr.s_addr = INADDR_ANY; - - int status = bind (maryDataSocket, (struct sockaddr*) &maryClient, sizeof (maryClient)); - - if (status != 0) - { - return -2; - } - - maryServer.sin_family = AF_INET; - maryServer.sin_port = htons (server_port); - memcpy ((char*) &maryServer.sin_addr.s_addr, hostInfo->h_addr_list [0], hostInfo->h_length); - - status = connect (maryDataSocket, (struct sockaddr*) &maryServer, sizeof (maryServer)); - - if (status != 0) - { - return -2; - } - } - - - // send the request id to the Mary server - if (send (maryDataSocket, id, strlen (id), 0) == -1) - { - return -2; - } - - //cout << "Sending request: " << inputText << endl; - - // send the query to the Mary server - if (send (maryDataSocket, inputText.c_str (), inputText.size (), 0) == -1) - { - return -2; - } - - if (send (maryDataSocket, "\012\015", 2, 0) == -1) - { - return -2; - } - - - // shutdown data socket - shutdown (maryDataSocket, 1); - - - //cout << "Reading result" << endl; - - unsigned int total_bytes = 0; - int recv_bytes = 0; - char data [1024] = ""; - - result [0] = '\0'; - - // receive the request result - do - { - data [0] = '\0'; - - recv_bytes = recv (maryDataSocket, data, 1024, 0); - - if (recv_bytes == -1) - { - return -2; - } - else if (recv_bytes > 0) - { - //cout << "("</libwsock32.a -#include -#else -#include -#endif - -#include -#include -#include - -#include "MaryClient.h" - -using namespace std; - -/** - * A C++ implementation of a simple client to the MARY TTS system. - * result: an empty string serving as the container for the output. - * It will return text or audio data; text data will be encoded as UTF-8. - * inputText: the UTF-8 encoded text (or XML document) to send as a request - * maryInFormat: the input type of the data in inputText, e.g. TEXT - * maryOutFormat: the output type to produce, e.g. MBROLA, AUDIO - * locale: the language of the input, e.g. EN-US, DE - * audioType: for AUDIO output, the type of audio data to produce, - * e.g. WAVE or MP3. - * voice: the voice to be used, e.g. cmu-slt-hsmm, bits3. - * effects: the list of effects to be generated. - * return value: 0 on success, negative on failure. - */ -int -MaryClient::maryQuery( int server_port, - string server_host, - string& result, - string inputText, - string maryInFormat, - string maryOutFormat, - string locale, - string audioType, - string voice, - string effects ) { - - // prepare the request - string query = "MARY"; - query += " IN=" + maryInFormat; - query += " OUT=" + maryOutFormat; - query += " LOCALE=" + locale; // remove this line, if using an older version than MARY 4.0 - query += " AUDIO=" + audioType; - query += " VOICE=" + voice; - if (effects != "") { - query += " EFFECTS=" + effects; - } - query += "\012\015"; - - //cout << "Constructed query: " << query << endl; - - // declare connection stuff - struct sockaddr_in maryServer; - struct sockaddr_in maryClient; - struct hostent* hostInfo; - - // declare variables - int maryInfoSocket; - int maryDataSocket; - - // set configuration parameters - - // get host information - hostInfo = gethostbyname (server_host.c_str()); - - if (hostInfo == NULL) - { - return -2; - } - - - // create a tcp connection to the mary server - maryInfoSocket = socket (AF_INET, SOCK_STREAM, 0); - - // verify that the socket could be opened successfully - if (maryInfoSocket == -1) - { - return -2; - } - else - // autoflush stdout, bind and connect - { - maryClient.sin_family = AF_INET; - maryClient.sin_port = htons (0); - maryClient.sin_addr.s_addr = INADDR_ANY; - - int status = bind (maryInfoSocket, (struct sockaddr*) &maryClient, sizeof (maryClient)); - - if (status != 0) - { - return -2; - } - - maryServer.sin_family = AF_INET; - maryServer.sin_port = htons (server_port); - memcpy ((char*) &maryServer.sin_addr.s_addr, hostInfo->h_addr_list [0], hostInfo->h_length); - - status = connect (maryInfoSocket, (struct sockaddr*) &maryServer, sizeof (maryServer)); - - if (status != 0) - { - return -2; - } - } - - // send request to the Mary server - if (send (maryInfoSocket, query.c_str (), query.size (), 0) == -1) - { - return -2; - } - - - // receive the request id - char id [32] = ""; - - if (recv (maryInfoSocket, id, 32, 0) == -1) - { - return -2; - } - - //cout << "Read id: " << id << endl; - - // create a tcp connection to the mary server - maryDataSocket = socket (AF_INET, SOCK_STREAM, 0); - - // verify that the socket could be opened successfully - if (maryDataSocket == -1) - { - return -2; - } - else - // autoflush stdout, bind and connect - { - maryClient.sin_family = AF_INET; - maryClient.sin_port = htons (0); - maryClient.sin_addr.s_addr = INADDR_ANY; - - int status = bind (maryDataSocket, (struct sockaddr*) &maryClient, sizeof (maryClient)); - - if (status != 0) - { - return -2; - } - - maryServer.sin_family = AF_INET; - maryServer.sin_port = htons (server_port); - memcpy ((char*) &maryServer.sin_addr.s_addr, hostInfo->h_addr_list [0], hostInfo->h_length); - - status = connect (maryDataSocket, (struct sockaddr*) &maryServer, sizeof (maryServer)); - - if (status != 0) - { - return -2; - } - } - - - // send the request id to the Mary server - if (send (maryDataSocket, id, strlen (id), 0) == -1) - { - return -2; - } - - //cout << "Sending request: " << inputText << endl; - - // send the query to the Mary server - if (send (maryDataSocket, inputText.c_str (), inputText.size (), 0) == -1) - { - return -2; - } - - if (send (maryDataSocket, "\012\015", 2, 0) == -1) - { - return -2; - } - - - // shutdown data socket - shutdown (maryDataSocket, 1); - - - //cout << "Reading result" << endl; - - unsigned int total_bytes = 0; - int recv_bytes = 0; - char data [1024] = ""; - - result [0] = '\0'; - - // receive the request result - do - { - data [0] = '\0'; - - recv_bytes = recv (maryDataSocket, data, 1024, 0); - - if (recv_bytes == -1) - { - return -2; - } - else if (recv_bytes > 0) - { - //cout << "("< -#include -#include - -#include "MaryClient.h" - -using namespace std; - -/** - * Demonstration code for using the MaryClient. - + Call this as: - * ./MaryDemo - * or - * ./MaryDemo > output.wav - */ -int main() { - int server_port = 59125; - string server_host = "localhost"; - string inputText = "Welcome to the world of speech synthesis!"; - string maryInFormat = "TEXT"; - string maryOutFormat = "AUDIO"; - //string maryOutFormat = "REALISED_DURATIONS"; - string locale = "en-US"; - string audioType = "WAV_FILE"; - string voice = "cmu-slt-hsmm"; - string effects; -// effects += "Volume(amount:5.0;)+"; -// effects += "TractScaler(amount:1.5;)+"; -// effects += "F0Scale(f0Scale:2.0;)+"; -// effects += "F0Add(f0Add:50.0;)+"; -// effects += "Rate(durScale:1.5;)+"; -// effects += "Robot(amount:100.0;)+"; -// effects += "Whisper(amount:100.0;)+"; -// effects += "Stadium(amount:100.0)+"; -// effects += "Chorus(delay1:466;amp1:0.54;delay2:600;amp2:-0.10;delay3:250;amp3:0.30)+"; -// effects += "FIRFilter(type:3;fc1:500.0;fc2:2000.0)+"; -// effects += "JetPilot"; - string result; - - MaryClient maryClient; - maryClient.maryQuery( server_port, server_host, result, inputText, maryInFormat, maryOutFormat, locale, audioType, voice, effects); - - if (maryOutFormat == "AUDIO") { - // write result into a file - const char *filename = "output.wav"; - ofstream file( filename ); - file << result; - - // play output - //system("play output.wav"); - } else { - cout << "RESULT: " << endl << result << endl; - } - - return 0; -} - diff --git a/external/marytts-5.1.2/doc/examples/client/c++/README.txt b/external/marytts-5.1.2/doc/examples/client/c++/README.txt deleted file mode 100755 index e38af989..00000000 --- a/external/marytts-5.1.2/doc/examples/client/c++/README.txt +++ /dev/null @@ -1,4 +0,0 @@ -Start MARY as a socket server: - -maryserver -Dserver=socket -(or change entry 'server' in conf/marybase.config) diff --git a/external/marytts-5.1.2/doc/examples/client/maryclient-http.py b/external/marytts-5.1.2/doc/examples/client/maryclient-http.py deleted file mode 100755 index cf9782e8..00000000 --- a/external/marytts-5.1.2/doc/examples/client/maryclient-http.py +++ /dev/null @@ -1,185 +0,0 @@ -#!/usr/bin/env python -import httplib, urllib - -# A basic mary client in Python, -# kindly donated to the MARY TTS project -# by Hugh Sasse. Thanks Hugh! - -# A very basic Python class for accessing -# the MARY TTS system using the modern -# HTTP server. -# Warning, this is probably ghastly Python, -# most of my time of late has been with -# other languages, so I'm not up to date -# with all the stylistic conventions of -# modern Python. -# This does seem to work OK though. - -class maryclient: - """A basic handler for MARY-TTS HTTP clients - - At present, there is no checking for - allowed voices, locales, and so on. - Most of the useful parameters can be - accessed by get_ and set_ methods. - Relying on winsound, this is Windows - specific. - """ - def __init__(self): - """Set up useful defaults (for - people in England, anyway)""" - self.host = "127.0.0.1" - self.port = 59125 - self.input_type = "TEXT" - self.output_type = "AUDIO" - self.audio = "WAVE_FILE" - self.locale = "en_GB" - self.voice = "dfki-prudence-hsmm" - - def set_host(self, a_host): - """Set the host for the TTS server.""" - self.host = a_host - - def get_host(self): - """Get the host for the TTS server.""" - self.host - - def set_port(self, a_port): - """Set the port for the TTS server.""" - self.port = a_port - - def get_port(self): - """Get the port for the TTS server.""" - self.port - - def set_input_type(self, type): - """Set the type of input being - supplied to the TTS server - (such as 'TEXT').""" - self.input_type = type - - def get_input_type(self): - """Get the type of input being - supplied to the TTS server - (such as 'TEXT').""" - self.input_type - - def set_output_type(self, type): - """Set the type of input being - supplied to the TTS server - (such as 'AUDIO').""" - self.output_type = type - - def get_output_type(self): - """Get the type of input being - supplied to the TTS server - (such as "AUDIO").""" - self.output_type - - def set_locale(self, a_locale): - """Set the locale - (such as "en_GB").""" - self.locale = a_locale - - def get_locale(self): - """Get the locale - (such as "en_GB").""" - self.locale - - def set_audio(self, audio_type): - """Set the audio type for playback - (such as "WAVE_FILE").""" - self.audio = audio_type - - def get_audio(self): - """Get the audio type for playback - (such as "WAVE_FILE").""" - self.audio - - def set_voice(self, a_voice): - """Set the voice to speak with - (such as "dfki-prudence-hsmm").""" - self.voice = a_voice - - def get_voice(self): - """Get the voice to speak with - (such as "dfki-prudence-hsmm").""" - self.voice - - def generate(self, message): - """Given a message in message, - return a response in the appropriate - format.""" - raw_params = {"INPUT_TEXT": message, - "INPUT_TYPE": self.input_type, - "OUTPUT_TYPE": self.output_type, - "LOCALE": self.locale, - "AUDIO": self.audio, - "VOICE": self.voice, - } - params = urllib.urlencode(raw_params) - headers = {} - - # Open connection to self.host, self.port. - conn = httplib.HTTPConnection(self.host, self.port) - - # conn.set_debuglevel(5) - - conn.request("POST", "/process", params, headers) - response = conn.getresponse() - if response.status != 200: - print response.getheaders() - raise RuntimeError("{0}: {1}".format(response.status, - response.reason)) - return response.read() - -# If this is invoked as a program, just give -# a greeting to show it is working. -# The platform specific code is moved to this -# part so that this file may be imported without -# bringing platform specific code in. -if __name__ == "__main__": - - # For handling command line arguments: - import sys - import platform - - # check we are on Windows: - system = platform.system().lower() - if (system == "windows"): - - import winsound - - class Player: - def __init__(self): - pass - - def play(self, a_sound): - winsound.PlaySound(a_sound, winsound.SND_MEMORY) - - #if ("cygwin" in system): - else: - # Not sure how to do audio on cygwin, - # portably for python. So have a sound - # player class that doesn't play sounds. - # A null object, if you like. - class Player: - def __init__(self): - pass - - def play(self, a_sound): - print("Here I would play a sound if I knew how") - pass - - # Probably want to parse arguments to - # set the voice, etc., here - - client = maryclient() - client.set_audio("WAVE_FILE") # for example - - player = Player() - the_sound = client.generate("hello from Mary Text to Speech, with Python.") - if client.output_type == "AUDIO": - player.play(the_sound) - -# vi:set sw=4 et: diff --git a/external/marytts-5.1.2/doc/examples/client/maryclient.cgi b/external/marytts-5.1.2/doc/examples/client/maryclient.cgi deleted file mode 100755 index 876a846e..00000000 --- a/external/marytts-5.1.2/doc/examples/client/maryclient.cgi +++ /dev/null @@ -1,177 +0,0 @@ -#!/usr/bin/perl -T -# -*- Mode: Perl -*- -# MARY Text-to-Speech System -# CGI Script implementing a simple mary client, -# can be used for web pages. -########################################################################## -# Copyright (C) 2000-2006 DFKI GmbH. -# All rights reserved. Use is subject to license terms. -# -# Permission is hereby granted, free of charge, to use and distribute -# this software and its documentation without restriction, including -# without limitation the rights to use, copy, modify, merge, publish, -# distribute, sublicense, and/or sell copies of this work, and to -# permit persons to whom this work is furnished to do so, subject to -# the following conditions: -# -# 1. The code must retain the above copyright notice, this list of -# conditions and the following disclaimer. -# 2. Any modifications must be clearly marked as such. -# 3. Original authors' names are not deleted. -# 4. The authors' names are not used to endorse or promote products -# derived from this software without specific prior written -# permission. -# -# DFKI GMBH AND THE CONTRIBUTORS TO THIS WORK DISCLAIM ALL WARRANTIES WITH -# REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF -# MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL DFKI GMBH NOR THE -# CONTRIBUTORS BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL -# DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR -# PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS -# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF -# THIS SOFTWARE. -########################################################################## -# Author: Marc Schroeder - -use strict; -use IO::Socket; -use CGI; - -# variables getting their values from form: -my ($inputtext, $in, $out, $audiotype, $voice); - -# little helpers: -my ($var, $tmp); - -# contacting the mary server: -my ($host, $port, $maryInfoSocket, $maryDataSocket, $id); - -# helping with audio output: -my ($save_to_disk, $audiosubtype, $filename); - - -my $cgi = new CGI; -my @param = $cgi->param(); -$inputtext = $cgi->param('inputtext'); -$in = $cgi->param('in'); -$out = $cgi->param('out'); -$audiotype = $cgi->param('audiotype'); -$save_to_disk = $cgi->param('save_to_disk'); -$voice = $cgi->param('voice'); - -my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst)=localtime(time); -$year += 1900; -printf STDERR "[%04i-%02i-%02i %02i:%02i:%02i] ", $year, $mon, $mday, $hour, $min, $sec; -print STDERR "Request from ",$cgi->remote_user(),"@",$cgi->remote_host(),": \n"; -print STDERR " in=",$in; -print STDERR " out=",$out; -print STDERR " audiotype=",$audiotype; -print STDERR " voice=",$voice; -print STDERR " save_to_disk=",$save_to_disk,"\n"; -print STDERR " inputtext: "; -print STDERR $inputtext,"\n"; - - -# Limit inputtext length to 5000 bytes: -if (length $inputtext > 5000) { - $inputtext = substr $inputtext, 0, 5000; -} - - -# set audio subtype -if ($out eq "AUDIO") { - if ($audiotype eq "AU") { - $audiosubtype = "basic"; - $filename = "mary.au"; - } elsif ($audiotype eq "AIFF") { - $audiosubtype = "x-aiff"; - $filename = "mary.aiff"; - } elsif ($audiotype eq "WAVE") { - $audiosubtype = "x-wav"; - $filename = "mary.wav"; - } elsif ($audiotype eq "MP3") { - $audiosubtype = "mp3"; - $filename = "mary.mp3"; - } else { - $audiosubtype = "x-wav"; - $filename = "mary.wav"; - } -} - -# announce data type on stdout -if ($save_to_disk) { - print "Content-Type: application/octet-stream"; -} else { - print "Content-Type: audio/$audiosubtype"; -} -print "\nContent-Disposition: filename=\"$filename\"\n\n"; - -# contact mary server -$host = "cling.dfki.uni-sb.de"; -$port = 59125; - -# create a tcp connection to the specified host and port -$maryInfoSocket = IO::Socket::INET->new(Proto => "tcp", - PeerAddr => $host, - PeerPort => $port) - or die "can't connect to port $port on $host: $!"; - -# avoid buffering when writing to server: -$maryInfoSocket->autoflush(1); # so output gets there right away - -########## Write input to server: ########## -# formulate the request: -print $maryInfoSocket "MARY IN=$in OUT=$out AUDIO=$audiotype"; -if ($voice && $voice ne 'v') { print $maryInfoSocket " VOICE=$voice"; } -print $maryInfoSocket " LOG=\"REMOTE_HOST=$ENV{'REMOTE_HOST'}", - ", REMOTE_ADDR=$ENV{'REMOTE_ADDR'}\""; -print $maryInfoSocket "\015\012"; - -# receive a request ID: -$id = <$maryInfoSocket>; - -# open second socket for the data: -$maryDataSocket = IO::Socket::INET->new(Proto => "tcp", - PeerAddr => $host, - PeerPort => $port) - or die "can't connect to port $port on $host: $!"; -# identify with request number: -print $maryDataSocket $id; # $id contains a newline character - -# copy $inputtext to mary data socket -print $maryDataSocket $inputtext; - -# mark end-of-request: -print $maryDataSocket "\015\012"; # that is a \n, actually -$maryDataSocket->shutdown(1); # we have stopped writing data - -########## Read output from server: ########## -# copy the data socket to standard output -if ($out ne "AUDIO") { # text output - my $line; - while (defined ($line = <$maryDataSocket>)) { - print STDOUT $line; - } -} else { # audio data output - my $nr; # number of bytes read - my $buf; # buffer to read into - my $outnr; # number of bytes written - while($nr = read($maryDataSocket, $buf, 8192)) { - # (read returns no. of bytes read, 0 at eof) - print STDOUT $buf - or die "Write error on stdout"; - } # while read something from socket -} # audio output - -### Read complaints from server: -my $line; -while (defined ($line = <$maryInfoSocket>)) { - print STDERR $line; -} - - - - - - - diff --git a/external/marytts-5.1.2/doc/examples/client/maryclient.pl b/external/marytts-5.1.2/doc/examples/client/maryclient.pl deleted file mode 100755 index 8b3f5f80..00000000 --- a/external/marytts-5.1.2/doc/examples/client/maryclient.pl +++ /dev/null @@ -1,136 +0,0 @@ -#!/usr/bin/env perl -# -# MARY Text-to-Speech System -# Minimal Socket client (for demonstration) -########################################################################## -# Copyright (C) 2000-2006 DFKI GmbH. -# All rights reserved. Use is subject to license terms. -# -# Permission is hereby granted, free of charge, to use and distribute -# this software and its documentation without restriction, including -# without limitation the rights to use, copy, modify, merge, publish, -# distribute, sublicense, and/or sell copies of this work, and to -# permit persons to whom this work is furnished to do so, subject to -# the following conditions: -# -# 1. The code must retain the above copyright notice, this list of -# conditions and the following disclaimer. -# 2. Any modifications must be clearly marked as such. -# 3. Original authors' names are not deleted. -# 4. The authors' names are not used to endorse or promote products -# derived from this software without specific prior written -# permission. -# -# DFKI GMBH AND THE CONTRIBUTORS TO THIS WORK DISCLAIM ALL WARRANTIES WITH -# REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF -# MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL DFKI GMBH NOR THE -# CONTRIBUTORS BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL -# DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR -# PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS -# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF -# THIS SOFTWARE. -########################################################################## -# Author: Marc Schroeder -# This is a minimal version of a socket client for the mary TtS system. -# It is intended to be used as a model for writing socket clients for -# particular applications. All input verification, command line options, -# and other luxury have been omitted. -# -# Usage: -# maryclient.pl infile.txt > outfile.wav -# -# Input/output formats and other options must be set in the perl code directly. -# See also Protocol.html for a description of the Protocol. -# - -use strict; -use IO::Socket; - -############################ -# Package-global variables # -############################ -# global settings: -my $maryInfoSocket; # handle to socket server -my $maryDataSocket; # handle to socket server -my $host; # string containing host address -my $port; # socket port on which we listen -my ($in, $out, $audiotype); # requested input / output format -my $voice; # default voice -my $id; # request ID - -###################################################################### -################################ main ################################ -###################################################################### - -STDOUT->autoflush(1); - -$host = "cling.dfki.uni-sb.de"; -$port = 59125; -$in = "TEXT_DE"; -$out = "AUDIO"; -$audiotype = "MP3"; -#$audiotype = "WAVE"; -#$voice = "male"; -$voice = "de3"; - -# create a tcp connection to the specified host and port -$maryInfoSocket = IO::Socket::INET->new(Proto => "tcp", - PeerAddr => $host, - PeerPort => $port) - or die "can't connect to port $port on $host: $!"; - -# avoid buffering when writing to server: -$maryInfoSocket->autoflush(1); # so output gets there right away - -########## Write input to server: ########## -# formulate the request: -print $maryInfoSocket "MARY IN=$in OUT=$out AUDIO=$audiotype"; -if ($voice) { print $maryInfoSocket " VOICE=$voice"; } -print $maryInfoSocket "\015\012"; - -# receive a request ID: -$id = <$maryInfoSocket>; -chomp $id; chomp $id; - -# open second socket for the data: -$maryDataSocket = IO::Socket::INET->new(Proto => "tcp", - PeerAddr => $host, - PeerPort => $port) - or die "can't connect to port $port on $host: $!"; -# identify with request number: -print $maryDataSocket $id, "\015\012"; - -# copy standard input and/or files given on the command line to the socket -while (defined (my $line = <>)) { - print $maryDataSocket $line; -} -# mark end-of-request: -print $maryDataSocket "\015\012"; # that is a \n, actually -shutdown($maryDataSocket, 1); # we have stopped writing data - -########## Read output from server: ########## -# copy the data socket to standard output -if ($out ne "AUDIO") { # text output - my $line; - while (defined ($line = <$maryDataSocket>)) { - print STDOUT $line; - } -} else { # audio data output - my $nr; # number of bytes read - my $buf; # buffer to read into - my $outnr; # number of bytes written - while($nr = read($maryDataSocket, $buf, 100000)) { - # (read returns no. of bytes read, 0 at eof) - print STDOUT $buf - or die "Write error on stdout"; - } # while read something from socket -} # audio output - -### Read complaints from server: -my $line; -while (defined ($line = <$maryInfoSocket>)) { - print STDERR $line; -} - - - diff --git a/external/marytts-5.1.2/doc/examples/client/maryclient.rb b/external/marytts-5.1.2/doc/examples/client/maryclient.rb deleted file mode 100755 index c4156cbb..00000000 --- a/external/marytts-5.1.2/doc/examples/client/maryclient.rb +++ /dev/null @@ -1,261 +0,0 @@ -#!/usr/bin/env ruby -# -# A basic mary client in Ruby, -# kindly donated to the MARY TTS project -# by Hugh Sasse. Thanks Hugh! - - -# Ruby client for the MARY TTS HTTP server. -# This is for Windows only, and relies on -# the Win32-Sound gem to access the audio. -# -# - -require 'rubygems' -require 'net/http' -require 'uri' - -# A fairly minimal client class for the -# MARY TTS system. This uses the modern -# HTTP interface to access the server. -# At present, this doesn't wrap the methods -# which provide documentation or lists of -# voices or features. -class MaryClient - attr_accessor :host, :port - attr_accessor :input_type, :output_type - attr_accessor :locale, :audio, :voice - - # Set up the defaults for the MARY TTS - # server, which is assumed to be running - # on the local host, with British voices - # installed. These may be modified with - # the appropriate methods. - # host = 127.0.0.1) - # port = 59125 - # input_type = "TEXT" - # output_type = "AUDIO" - # audio = "WAVE_FILE" - # locale = "en_GB" - # voice = "dfki-prudence-hsmm" - def initialize - @host = "127.0.0.1" # The local machine - @port = 59125 - @input_type = "TEXT" - @output_type = "AUDIO" - @locale = "en_GB" - @audio = "WAVE_FILE" - @voice = "dfki-prudence-hsmm" - end - - # Process a text message, which with a - # new client, will return the audio. - # This is so that platform dependent parts - # are kept separate. - def generate(message) - raw_params = {"INPUT_TEXT" => message, - "INPUT_TYPE" => @input_type, - "OUTPUT_TYPE" => @output_type, - "LOCALE" => @locale, - "AUDIO" => @audio, - "VOICE" => @voice, - } - res = Net::HTTP.post_form(URI.parse("http://#{@host}:#{@port}/process"), raw_params) - res.value # Throw an exception on failure - #puts res.body - return res.body - end -end - - -# If this invoked as a program with no -# argumens, just give a greeting to show -# that it is working. If arguments are -# supplied, process options to work out -# what to do with the arguments. -if __FILE__ == $0 - - # These files are only loaded when this is - # invoked as a program. - require 'rbconfig' - require 'getoptlong' - - # PLATFORM SPECIFIC CODE. - # Needs more work [!] - case Config::CONFIG['host_os'] - when /darwin/i - raise NotImplementedError.new("Don't know how to play audio on a Mac") - when /linux/i - raise NotImplementedError.new("Far too many ways to play audio on Linux, you'll need to choose something") - when /sunos|solaris/i - raise NotImplementedError.new("Have not played audio on Suns for too long to implement this.") - when /java/i - raise NotImplementedError.new("Don't know how to play audio from Java ") - when /win32|cygwin|mingw32/i - # The various things that can use the Win32 - # sound gem - require 'win32/sound' - # Create a player class that will play the - # sound that the Mary TTS system returns - class Player - - # Play the audio passed in. - # Possibly this should receive the audio - # type so we can check that we can play it, - # but at the moment that is the - # responsibility of the user. - def self.play(sound) - Win32::Sound.play(sound, Win32::Sound::MEMORY) - end - end - else - raise NotImplementedError.new("Haven't thought how to support this OS yet") - end - - - client = nil - split = "" - - if ARGV.size.zero? - client = MaryClient.new() - sound = client.generate("Hello from Mary Text to Speech with Ruby.") - Player.play(sound) - else - args_mode = :words - stdout_mode = :absorb - opts = GetoptLong::new( - ["--audio", "-a", GetoptLong::REQUIRED_ARGUMENT], - ["--echo", "-e", GetoptLong::NO_ARGUMENT], - ["--help", "-h", GetoptLong::NO_ARGUMENT], - ["--host", "-H", GetoptLong::REQUIRED_ARGUMENT], - ["--input-type", "-i", GetoptLong::REQUIRED_ARGUMENT], - ["--locale", "-l", GetoptLong::REQUIRED_ARGUMENT], - ["--read", "-r", GetoptLong::NO_ARGUMENT], - - ["--split", "-s", GetoptLong::REQUIRED_ARGUMENT], - ["--output-type", "-o", GetoptLong::REQUIRED_ARGUMENT], - ["--port", "-P", GetoptLong::REQUIRED_ARGUMENT], - ["--tee", "-t", GetoptLong::NO_ARGUMENT], - ["--voice", "-v", GetoptLong::REQUIRED_ARGUMENT] - ) - - opts.each do |opt, arg| - unless ["--help", "-h"].include?(opt) - # skip if we are only getting help - client ||= MaryClient.new() - end - case opt - when "--help", "-h" - puts <<-EOHELP -Usage: #{$0} [options] [arguments] ---audio -a - Audio format. Defualt: WAVE_FILE ---echo -e - Act as an echo command and send output - arguments to the synthesizer only (not - to standard output. - Turns off --read|-r ---help -h - Print this help, then exit. ---host -H - The host which is the server. - Default: 127.0.0.1 ---input-type -i - The type of the input supplied to the - TTS system. Default: TEXT ---locale -l - The locale of the input. Default: en_GB ---output-type -o - The output type from the TTS system. - Default: AUDIO ---port -P - The port for the TTS server - Default: 59125 ---read -r - Read the files passed as arguments. - Turns off --echo|-e ---split -s (lines|paragraphs) - When reading files, split the input - into lines or paragraphs. Paragraphs - mean reading up to the next double - newline. Note, the argument is literally - "lines" or "paragraphs" (or some - abbreviation of those) without the - quotes. - Default is paragraphs. ---tee -t - Act as tee: send the output to the TTS - system, and to standard output. ---voice -v - The voice to use. - Default: dfki-prudence-hsmm - EOHELP - exit(0) - when "--audio", "-a" - client.audio = arg - when "--echo", "-e" - args_mode = :words - when "--host", "-H" - client.host = arg - when "--input-type", "-i" - client.input_type = arg - when "--locale", "-l" - client.locale = arg - when "--output-type", "-o" - client.output_type = arg - when "--port", "-P" - client.port = arg.to_i - when "--read", "-r" - args_mode = :files - when "--split", "-s" - case arg - when /^p/i - split = "" - when /^l/i - split = $/ - end - when "--tee", "-t" - stdout_mode = :emit - when "--voice", "-v" - client.voice = arg - end - end - - client ||= MaryClient.new() - case args_mode - when :words - input_text = ARGV.join(" ") - unless input_text =~ /\A\s*\Z/m - sound = client.generate(input_text) - if client.output_type == "AUDIO" - Player.play(sound) - end - end - if stdout_mode == :emit - puts input_text - end - when :files - # Slurp in paragraphs so sentences - # don't get broken in stupid places. - $/ = split # paragraph mode - ARGF.each do |paragraph| - begin - unless paragraph =~ /\A\s*\Z/m - sound = client.generate(paragraph) - if client.output_type == "AUDIO" - # and client.audio == "WAVE_FILE" - Player.play(sound) - end - end - rescue Exception => e - puts "got error #{e} while trying to say #{paragraph.inspect}" - raise - end - if stdout_mode == :emit - puts paragraph - end # end if - end # end ARGF.each - end # end case - end # if ARGV.size.zero? -end - diff --git a/external/marytts-5.1.2/doc/examples/client/maryclient.tcl b/external/marytts-5.1.2/doc/examples/client/maryclient.tcl deleted file mode 100755 index 3a358235..00000000 --- a/external/marytts-5.1.2/doc/examples/client/maryclient.tcl +++ /dev/null @@ -1,705 +0,0 @@ -# Tcl/Tk MARY TTS client. - -# This has been tested on Windows, and because -# of the use of sound there will be portability -# issues. However, there should be enough here -# for a reasonable start at a client, for any -# platform that supports Tcl/Tk. The platform -# specific code has, as far as possible, been -# isolated in the part of the code that detects -# whether this is being run as a program. - -# Notes: -# More work will need to be done with this, -# in order to make the code clean. It should -# probably be wrapped in a package, to solve -# any namespace issues. There are a lot of -# global variables. It seems that some of -# these are necessary for the menus to work. -# Handling of temporary files could be improved. - -# TODO: -# Create modifier sliders, for the effects. -# Extend the query proc to make use of them. -# Turn the Help menu into something more useful. -# Debug the actions for the Edit menu. -# Provide a means of getting example inputs -# from the server. -# Provide a means of re-loading all the -# dynamically collected information when the -# server is changed from the menu. This means -# that we need to delete the existing menu -# entries in order to add them correctly. -# How do we ensure temporary files are removed -# in the event of a problem? if {catch {}} ...? -# Maybe leaving them around is diagnostic info? -# Make that an option? -# Add error handling code for network and disk -# failures likely to beset such clients. -# Add sensible defaults for things the user must -# always set at startup, but these will be -# platform spacific. Always default to Audio -# output for example, or is it possible that -# people have no voices installed? - - -# This is a GUI, so: -package require Tk - -# We are communicating with the Mary server -# with HTTP. -package require http - -# Use the local machine in preference to the -# one in Germany. -set mary_tts_default_host "127.0.0.1" -set mary_tts_default_port 59125 - -# Actual host and port, and global old -# copies to allow revert on cancel in the -# dialogues. Apparently upvar #0 is the -# norm for that sort of thing [Tcl Wiki] -set mary_tts_host $mary_tts_default_host -set old_mary_tts_host $mary_tts_host -set mary_tts_port $mary_tts_default_port -set old_mary_tts_port $mary_tts_port - -# Informational URLs -set informational_urls [ list \ -version datatypes voices \ -audioformats audioeffects ] - -####### - -# Obtain a static page from the server, i.e. -# no parameters are needed to get it. -proc get_page { relative_url } { - global mary_tts_host mary_tts_port - set url http://$mary_tts_host:$mary_tts_port/$relative_url - set result [::http::geturl $url] - return [::http::data $result] -} - -proc list_of_lines {str} { - return [ split $str "\n" ] -} - - -# We will need to collect this information -# when we have the server and port chosen. -proc get_audioeffects {} { - return [list_of_lines [get_page audioeffects] ] -} - -proc get_audioformats {} { - return [list_of_lines [get_page audioformats] ] -} - -proc get_datatypes {} { - return [ list_of_lines [get_page datatypes] ] -} - - -proc get_voices {} { - return [list_of_lines [get_page voices] ] -} - -# Handling post queries. - -# Submit the query to the server, using the -# http POST method. -proc make_query {url encoded_params} { - set http [::http::geturl $url -query $encoded_params] - set result [::http::data $http] - return $result -} - -# Get the text from the input text area -proc get_input_text {} { - return [.io.inp.input_area get 1.0 end] -} - -# Get the text from the output text area -proc get_output_text {} { - return [.io.out.output_area get 1.0 end] -} - -# Collect the audio data from the server. -proc collect_audio_data {text_to_process} { - global mary_tts_host mary_tts_port - global inputtype outputtype locales - global audioformat voice - set url "http://$mary_tts_host:$mary_tts_port/process" - # ::http::formatQuery converts a list of - # key value pairs into the correct format - # for http POST. - set params [::http::formatQuery INPUT_TEXT $text_to_process INPUT_TYPE $inputtype OUTPUT_TYPE $outputtype LOCALE $locales($voice) AUDIO $audioformat VOICE $voice ] - set result [make_query $url $params] - return $result -} - -# Pushes the query to the server and gets -# the results back, displaying or playing -# them. -proc generate_output {text_to_process} { - global outputtype - set result [collect_audio_data $text_to_process] - if {$outputtype eq "AUDIO"} { - # call the platform dependent implementation. - play $result - } else { - clear_output - add_message $result - } - # Return the result so we can save it if - # the user requires it. - return $result -} - - -# These next procs are for handling the -# lists of data one gets back from the server -# which possibly have several words per line, -# separated by spaces. - -# If the first word of each listed line is -# significant, extract the list of first words. -proc collect_first_words_of_phrase_list {a_list} { - for {set i 0} {$i < [llength $a_list]} {incr i} { - set data [lindex $a_list $i ] - set word [ lindex [split $data " "] 0 ] - lappend words $word - } - return $words -} - - -# If the second word of each listed line is -# significant, extract the list of second words. -proc collect_second_words_of_phrase_list {a_list} { - for {set i 0} {$i < [llength $a_list]} {incr i} { - set data [lindex $a_list $i ] - set word [ lindex [split $data " "] 1 ] - lappend words $word - } - return $words -} - - -# The list of datatypes must be separated into -# input data types and output data types so that -# interactions with the server make sense. -# This handles the inputs. -proc collect_first_words_of_input_types {a_list} { - for {set i 0} {$i < [llength $a_list]} {incr i} { - set data [lindex $a_list $i ] - if {[ string match -nocase "*input*" $data ]} { - set word [ lindex [split $data " "] 0 ] - lappend words $word - } - } - return $words -} - - -# The list of datatypes must be separated into -# input data types and output data types so that -# interactions with the server make sense. -# This handles the outputs. -proc collect_first_words_of_output_types {a_list} { - for {set i 0} {$i < [llength $a_list]} {incr i} { - set data [lindex $a_list $i ] - if {[string match -nocase "*output*" $data]} { - set word [ lindex [split $data " "] 0 ] - lappend words $word - } - } - return $words -} - -# setup all the variables to hold voices, -# audio options, etc., based on what the -# server can do. -proc setup_globals {} { - global audioeffects audioformats voices - global inputtypes outputtypes audioformat voice - global inputtype outputtype locales - - set audioeffects [get_audioeffects] - set audioformats [get_audioformats] - set audioformat [lindex $audioformats 0 ] - set datatypes_data [get_datatypes] - set inputtypes [collect_first_words_of_input_types $datatypes_data] - set inputtype [lindex $inputtypes 0] - set outputtypes [collect_first_words_of_output_types $datatypes_data] - set outputtype [lindex $outputtypes 0] - set voices_data [get_voices] - set voices [collect_first_words_of_phrase_list $voices_data] - set locales_list [collect_second_words_of_phrase_list $voices_data ] - for {set i 0} {$i < [llength $voices]} {incr i} { - set locales([lindex $voices $i]) [lindex $locales_list $i] - } - set voice [lindex $voices 0] -} - -# A general procedure for filling in the -# elements of a listbox from a list. -# At present this is unused, but it could -# be useful later. [It took a while to -# figure out so I'm not ready to kill it -# with YAGNI.] -proc add_listbox_items {a_var a_widget} { - upvar $a_var var - foreach item $var { - $a_widget insert end $item - } -} - -# Create the menubuttons along the top. -# Usual File, Edit and Help menus plus -# those to set attributes. -proc create_menubuttons {} { - set buttons [ list file File edit Edit \ - server "Server" \ - inputtype "Input type" outputtype "Output type" \ - voice Voice \ - audioformat "Audio format" \ - textstyle "Text style" help Help ] - - set count 1 - foreach { menu_tag string_tag} $buttons { - menubutton .menus.$menu_tag -text $string_tag \ - -menu .menus.${menu_tag}.menu -underline 0 -font ClientFont - menu .menus.${menu_tag}.menu -tearoff true - grid .menus.$menu_tag -in .menus -row 1 -column $count -sticky w - incr count - } -} - -# Get the contents of a text file for reading -# or loading into a text widget, etc. -proc text_file_contents {what_for} { - set a_file [tk_getOpenFile -title $what_for ] - set the_text "" - - if {$a_file != ""} { - set a_stream [open $a_file r ] - set the_text [read $a_stream] - close $a_stream - } - - return $the_text -} - - -# Save the_text to a text file specified -# by the user, for the given reason (what_for). -# At the moment there is no error handling -# for this (disk full, write protected, etc). -proc save_text_file {the_text what_for} { - set a_file [tk_getSaveFile -title $what_for -parent .] - if {$a_file != ""} { - set a_stream [open $a_file w ] - puts $a_stream $the_text - close $a_stream - } -} - -# Save the_data to a binary file specified -# by the user, for the given reason (what_for), -# a text string. -# At the moment there is no error handling -# for this (disk full, write protected, etc). -proc save_binary_file {the_data what_for} { - set a_file [tk_getSaveFile -title $what_for -parent .] - if {$a_file != ""} { - set a_stream [open $a_file w ] - fconfigure $a_stream -translation binary - puts -nonewline $a_stream $the_data - close $a_stream - } -} - -# Create the menu for File operations -proc create_menu_file {} { - set fmenu .menus.file.menu - $fmenu add command -label "New" \ - -font ClientFont -command { - .io.inp.input_area delete 1.0 end - } - # Replace the contents of the input text - # widget by the data from the open file. - # YAGNI, but is there any reason - # to allow inserting a file, rather than - # replacing the text with file contents? - # - $fmenu add command -label "Open" \ - -font ClientFont -command { - set the_text [text_file_contents "File to load"] - if {$the_text != ""} { - .io.inp.input_area delete 1.0 end - .io.inp.input_area insert end $the_text - } - } - - $fmenu add command -label "Read" \ - -font ClientFont -command { - generate_output [text_file_contents "File to read"] - } - # How to make these disabled for now? - $fmenu add command -label "Save Input" \ - -font ClientFont -command { - set the_text [get_input_text] - save_text_file $the_text "Save Input" - } - $fmenu add command -label "Save Output" \ - -font ClientFont -command { - set the_text [get_output_text] - save_text_file $the_text "Save Output" - } -} - -# Create the menu for edit operations -proc create_menu_edit {} { - set emenu .menus.edit.menu - $emenu add command -label "Select All from Input Area" \ - -font ClientFont -command { - # This code says copy the selection as well. - # May be wrong for some platforms, but is - # it more useful? - .io.inp.input_area tag add sel 1.0 end - event generate .io.inp.input_area <> -} - $emenu add command -label "Select All from Output Area" \ - -font ClientFont -command { - # This code says copy the selection as well. - # May be wrong for some platforms, but is - # it more useful? - .io.out.output_area tag add sel 1.0 end - event generate .io.out.output_area <> -} - $emenu add command -label "Copy from Input Area" \ - -font ClientFont -command { - # this appears not to work. FIXME - event generate .io.inp.input_area <> - } - $emenu add command -label "Copy from Output Area" \ - -font ClientFont -command { - # this appears not to work. FIXME - event generate .io.out.output_area <> - } - $emenu add command -label "Paste into Input Area" \ - -font ClientFont -command { - # this appears not to work. FIXME - event generate .io.inp.input_area <> - } - $emenu add command \ - -font ClientFont -label "Insert example text into Input Area"\ - -command { - } - # Add specific editing commands here later. - # For example, we would like to be able to - # add whole tags to the XML based formats, - # wrap matching tags around selected text. - # Also we need to find out what happens with - # copy cut and paste, given that X Windows - # is different from MS Windows. - # Allow example text to be inserted. - # However, my thinking is that this should not - # overwrite as it is in the Java application, - # because this rubs out edits when switching - # voices, and this can be annoying when - # exploring the system. -} - -# Set the server properties, mostly just -# host and port. Maybe later protocol will -# be possible for https connections? -proc create_menu_server {} { - set smenu .menus.server.menu - $smenu add command -label "host" -font ClientFont -command { - create_entry_dialog "MARY TTS server name" "hostname/IP Address" mary_tts_host - } - $smenu add command -label "port" -font ClientFont -command { - create_entry_dialog "MARY TTS server port" "pott number" mary_tts_port - } -} - -# setup the fonts for the various areas on the dipslay. -proc setup_font {family size} { - foreach win {.io .controls .entry.dialogue } { - font configure ClientFont -family $family -size $size - } -} - -# Create the menu for changing the text size. -proc create_menu_textstyle {} { - set tmenu .menus.textstyle.menu - - $tmenu add cascade -label "Courier" -underline 0 -menu \ - $tmenu.courier -font ClientFont - $tmenu add cascade -label "Times" -underline 0 -menu \ - $tmenu.times -font ClientFont - $tmenu add cascade -label "Helvetica" -underline 0 -menu \ - $tmenu.helvetica -font ClientFont - foreach {name family} [list $tmenu.courier Courier \ - $tmenu.times Times $tmenu.helvetica Helvetica ] { - set m1 [menu $name] - foreach pts {6 7 8 9 10 12 14 16 18 20 24 28 32 36} { - $m1 add command -label "$pts" -font ClientFont\ - -command [list setup_font $family $pts ] - } - } -} - - - -# Create the menu for Help -proc create_menu_help {} { - # This is all pretty much "wet paint" - # Is there enough to merit separate menus? - set hmenu .menus.help.menu - $hmenu add command -label "Introduction" -font ClientFont\ - -command { - tk_messageBox -message "This is a basic Tcl/Tk -client for the MARY TTS system. Most of the options -are reached through the menus on the top. Some -facilities are presently lacking. - -Most of the interface should be self-explanatory. -In the File menu, Read will read a given file aloud -(or at least take it as input for the present -form of processing), whereas Open will load it -into the input area. Save input and Save output -refer to the contents of the text windows. The -save button next to the play button will save -the output to a file; this is assumed to be a -text file, unless the output is audio, in which -case it is a binary file. - -The Edit menu has cut and paste facilities, -but these don't seem to work reliably. The -default key bindings for text areas should -be useable. - -You will need to set the input and output types -and the audio format before pressing play. -Code does not yet exist to figure out sensible -defaults for your platform. - -This does not have support for the effects, yet. - -Contributions from developers welcome." -type ok - } - $hmenu add command -label "About" -command {} -font ClientFont -} - -# We need to create menus for the available -# voices and audio formats, etc. -# When we have the data for these menus from -# the server, create them by using the global -# lists of information. -proc create_radio_menu_from_list {what} { - global $what - set plural "${what}s" - upvar 1 $plural var - foreach item $var { - .menus.${what}.menu add radiobutton -label $item -variable $what \ - -value $item -font ClientFont - } -} - -proc reset_entry_and_var {a_variable} { - upvar #0 $a_variable var - upvar #0 old_$a_variable old_var - set var $old_var - destroy .entry_dialogue -} -# Create the toplevel for choosing a host -# or port, something taken from an entry. -proc create_entry_dialog {a_message a_label a_variable} { - upvar #0 $a_variable var - upvar #0 old_$a_variable old_var - toplevel .entry_dialogue - label .entry_dialogue.the_message -text $a_message \ - -font ClientFont - label .entry_dialogue.the_label -text $a_label -font ClientFont - entry .entry_dialogue.the_entry -textvariable $a_variable \ - -font ClientFont - button .entry_dialogue.ok -text "OK" -font ClientFont -command { - destroy .entry_dialogue - } - button .entry_dialogue.cancel -text "Cancel" -font ClientFont \ - -command "reset_entry_and_var $a_variable" - - grid .entry_dialogue.the_message -row 1 -column 1 - grid .entry_dialogue.the_label -row 2 -column 1 - grid .entry_dialogue.the_entry -row 2 -column 2 - grid .entry_dialogue.ok -row 3 -column 1 - grid .entry_dialogue.cancel -row 3 -column 2 -} - -# Add a message to the end of the output -# text widget. -proc add_message {a_message} { - .io.out.output_area configure -state normal - .io.out.output_area insert end $a_message - .io.out.output_area configure -state disabled -} - - -# Clear the text in the output text widget. -proc clear_output {} { - .io.out.output_area configure -state normal - .io.out.output_area delete 1.0 end - .io.out.output_area configure -state disabled -} - -# Sound generation is platform dependent. -# This provides an "abstract" function to -# be overridden by the platform dependent -# code. In this case it alerts the user -# in the output window that nothing is going -# to happen. -proc play {sound} { - add_message \ - "play sound not implemented on this platform apparently" -} - -# Graphical stuff. - -# In order to be able to scale the font, define a font. -font create ClientFont -family [font actual TkDefaultFont -family] \ - -size [font actual TkDefaultFont -size] - -frame .menus -create_menubuttons -create_menu_file -create_menu_edit -create_menu_server -create_menu_textstyle -create_menu_help -# Fill in the other menus at runtime. - -# .io communicates text with the user, -# through an input and output window. -frame .io -frame .io.inp -frame .io.out -# .controls will hold the play button and -# the effects controls. -frame .controls - -# Draw the controls in .io -label .io.inp.input_label -text "Input Area" -font ClientFont -text .io.inp.input_area -height 10 -width 40 \ --xscrollcommand ".io.inp.input_x set" \ --yscrollcommand ".io.inp.input_y set" -font ClientFont -scrollbar .io.inp.input_x -orient horizontal \ --command ".io.inp.input_area xview" -scrollbar .io.inp.input_y -orient vertical \ --command ".io.inp.input_area yview" - -label .io.out.output_label -text "Output Area" -font ClientFont -text .io.out.output_area -height 10 -width 40 -state disabled \ --xscrollcommand ".io.out.output_x set" \ --yscrollcommand ".io.out.output_y set" -font ClientFont -scrollbar .io.out.output_x -orient horizontal \ --command ".io.out.output_area xview" -scrollbar .io.out.output_y -orient vertical \ --command ".io.out.output_area yview" - -grid .io.inp -in .io -row 1 -column 1 -grid .io.out -in .io -row 1 -column 2 -grid .io.inp.input_label -in .io.inp -row 1 -column 1 -grid .io.inp.input_area -in .io.inp -row 2 -column 1 -grid .io.inp.input_y -in .io.inp -row 2 -column 2 -sticky ns -grid .io.inp.input_x -in .io.inp -row 3 -column 1 -sticky ew - -grid .io.out.output_label -in .io.out -row 1 -column 1 -grid .io.out.output_area -in .io.out -row 2 -column 1 -grid .io.out.output_y -in .io.out -row 2 -column 2 -sticky ns -grid .io.out.output_x -in .io.out -row 3 -column 1 -sticky ew - -button .controls.play -text "play" -font ClientFont -command { - generate_output [get_input_text] -} -grid .controls.play -in .controls -row 1 -column 1 - -button .controls.save -text "save" -font ClientFont -command { - global outputtype - set input_text [get_input_text] - if { $outputtype eq "AUDIO" } { - save_binary_file [collect_audio_data $input_text ] "Save audio file" - } else { - save_text_file [collect_audio_data $input_text ] "Save output to file" - } -} - -grid .controls.save -in .controls -row 1 -column 2 - -pack .menus .io .controls -in . -side top - - - -# Detect whether this is the main program -# This test was taken from the Tcl Wiki, and -# seems to work OK. - -if {[info exists argv0] && [file tail [info script]] eq [file tail $argv0]} { - - # Try to find the temporary files directory. - catch { set tmpdir "/tmp" } - catch { set tmpdir $::env(TRASH_FOLDER) } - catch { set tmpdir $::env(TMP) } - catch { set tmpdir $::env(TEMP) } - # This needs better handling of - # possible alternatives - # This is needed for Windows sound only. - - # Do the platform dependent things. - if {$tcl_platform(platform) eq "windows"} { - package require twapi - - proc play {sound} { - global tmpdir - # Write sound to a temporary file - set sndfile [file join $tmpdir "MARYTTS_sound.[pid].wav" ] - set stream [open $sndfile w] - # Make sure the file is binary: - fconfigure $stream -translation binary - puts -nonewline $stream $sound - close $stream - # Play the file. - ::twapi::play_sound $sndfile - # Remove the file. - file delete $sndfile - } - } - # Put other platforms here. - - # Setup the globals with reference to the - # server, which is assumed to be working. - # Since we have options to alter this with - # menu items, there probably needs to be - # some way to reload all this. But we need - # to know how to delete the existing menu - # entries to do that. - setup_globals - create_radio_menu_from_list inputtype - create_radio_menu_from_list outputtype - create_radio_menu_from_list voice - create_radio_menu_from_list audioformat - - # Note, at the moment voices holds locales, - # gender, and voice type - - # At the moment this is just diagnostic: - ## add_message [ join $voices "\n" ] - # it tells us we have a basically working - # system and the list of voices has been - # picked up and manipulated correctly. - # So it is commented out now. -} - - diff --git a/external/marytts-5.1.2/doc/examples/client/texttospeechdemo.html b/external/marytts-5.1.2/doc/examples/client/texttospeechdemo.html deleted file mode 100755 index e788cf50..00000000 --- a/external/marytts-5.1.2/doc/examples/client/texttospeechdemo.html +++ /dev/null @@ -1,81 +0,0 @@ - - - - - - + + + + +
+ + \ No newline at end of file diff --git a/hal-core/resources/web/api/openapi.json b/hal-core/resources/web/api/openapi.json new file mode 100644 index 00000000..a3dbf042 --- /dev/null +++ b/hal-core/resources/web/api/openapi.json @@ -0,0 +1,313 @@ +{ + "components": { + "schemas": { + "alertClass": { + "type": "object", + "properties": { + "id": {"type": "integer"}, + "level": {"type": "string"}, + "ttl": {"type": "integer"}, + "title": {"type": "string"}, + "description": {"type": "string"} + } + }, + + "eventClass": { + "type": "object", + "properties": { + "data": { + "type": "object", + "$ref": "#/components/schemas/dataClass" + }, + "dataType": {"type": "string"}, + "name": {"type": "string"}, + "id": {"type": "integer"}, + "map": { + "type": "object", + "$ref": "#/components/schemas/mapClass" + }, + "user": {"type": "string"}, + "config": { + "type": "object", + "$ref": "#/components/schemas/configClass" + }, + "configType": {"type": "string"} + } + }, + + "roomClass": { + "type": "object", + "properties": { + "id": {"type": "integer"}, + "name": {"type": "string"}, + "map": { + "type": "object", + "$ref": "#/components/schemas/mapClass" + } + } + }, + + "sensorClass": { + "type": "object", + "properties": { + "data": { + "type": "object", + "$ref": "#/components/schemas/dataClass" + }, + "name": {"type": "string"}, + "id": {"type": "integer"}, + "map": { + "type": "object", + "$ref": "#/components/schemas/mapClass" + }, + "user": {"type": "string"}, + "config": { + "type": "object", + "$ref": "#/components/schemas/configClass" + }, + "aggregate": { + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "type": "number" + } + }, + "timestamps": { + "type": "array", + "items": { + "type": "integer" + } + } + } + } + } + }, + + "configClass": { + "type": "object", + "properties": { + } + }, + + "dataClass": { + "type": "object", + "properties": { + "valueStr": {"type": "string"}, + "value": {"type": "number"}, + "timestamp": {"type": "integer"} + } + }, + + "mapClass": { + "type": "object", + "properties": { + "x": {"type": "number"}, + "y": {"type": "number"}, + "width": {"type": "number"}, + "height": {"type": "number"} + } + }, + } + }, + + "servers": [ + { + "description": "Hal Server", + "url": "/api" + } + ], + + "openapi": "3.0.1", + + "paths": { + "/alert": { + "get": { + "responses": { + "200": { + "description": "A successful response.", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "type": "object", + "$ref": "#/components/schemas/alertClass" + } + } + } + } + } + }, + "parameters": [ + { + "schema": { + "type": "string", + "enum": [ + "poll", + "peek", + "dismiss" + ] + }, + "in": "query", + "name": "action", + "required": true + }, + { + "schema": { + "type": "integer" + }, + "in": "query", + "name": "id", + "required": false + } + ] + } + }, + + "/event": { + "get": { + "responses": { + "200": { + "description": "A successful response.", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "type": "object", + "$ref": "#/components/schemas/eventClass" + } + } + } + } + } + }, + "parameters": [ + { + "schema": { + "type": "integer" + }, + "in": "query", + "name": "id", + "required": false + }, + { + "schema": { + "type": "string" + }, + "in": "query", + "name": "configType", + "required": false + }, + { + "schema": { + "type": "string" + }, + "in": "query", + "name": "dataType", + "required": false + } + ] + } + }, + + "/room": { + "get": { + "responses": { + "200": { + "description": "A successful response.", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "type": "object", + "$ref": "#/components/schemas/roomClass" + } + } + } + } + } + }, + "parameters": [ + { + "schema": { + "type": "integer" + }, + "in": "query", + "name": "id", + "required": false + } + ] + } + }, + + "/sensor": { + "get": { + "responses": { + "200": { + "description": "A successful response.", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "type": "object", + "$ref": "#/components/schemas/sensorClass" + } + } + } + } + } + }, + "parameters": [ + { + "schema": { + "type": "integer" + }, + "in": "query", + "name": "id", + "required": false + }, + { + "schema": { + "type": "string" + }, + "in": "query", + "name": "configType", + "required": false + }, + { + "schema": { + "type": "string" + }, + "in": "query", + "name": "dataType", + "required": false + }, + { + "schema": { + "type": "string", + "enum": [ + "min", + "hour", + "day", + "week" + ] + }, + "in": "query", + "name": "aggregation", + "required": false + } + ] + } + } + }, + "info": { + "description": "This API allows developers and external tools to interface to Hal data and trigger different actions.", + "title": "Hal REST API", + "version": "" + } +} \ No newline at end of file diff --git a/hal-core/resources/web/css/hal.css b/hal-core/resources/web/css/hal.css new file mode 100644 index 00000000..030b1863 --- /dev/null +++ b/hal-core/resources/web/css/hal.css @@ -0,0 +1,233 @@ +/* + * Base structure + */ + +/* Move down content because we have a fixed navbar that is 50px tall */ +body { + padding-top: 50px; +} + + +/* + * Global add-ons + */ + +.sub-header { + padding-bottom: 10px; + border-bottom: 1px solid #eee; +} + +/* + * Top navigation + * Hide default border to remove 1px line. + */ +.navbar-fixed-top { + border: 0; +} + +/* + * Sidebar + */ + +/* Hide for mobile, show later */ +.sidebar { + display: none; +} +@media (min-width: 768px) { + .sidebar { + position: fixed; + top: 51px; + bottom: 0; + left: 0; + z-index: 1000; + display: block; + padding: 20px; + overflow-x: hidden; + overflow-y: auto; /* Scrollable contents if viewport is shorter than content. */ + background-color: #f5f5f5; + border-right: 1px solid #eee; + } +} + +/* Sidebar navigation */ +.nav-sidebar { + margin-right: -21px; /* 20px padding + 1px border */ + margin-bottom: 20px; + margin-left: -20px; +} +.nav-sidebar > li > a { + padding-right: 20px; + padding-left: 20px; +} +.nav-sidebar > .active > a, +.nav-sidebar > .active > a:hover, +.nav-sidebar > .active > a:focus { + color: #fff; + background-color: #428bca; +} + + +/* + * Main content + */ + +.main { + padding: 20px; +} +@media (min-width: 768px) { + .main { + padding-right: 40px; + padding-left: 40px; + } +} +.main .page-header { + margin-top: 0; +} + +.vertical-space { + height: 70px; +} +.text-vert-middle { + vertical-align: middle !important; +} + +.table-borderless tbody tr td { + border: none; +} + +.drop-shadow { + box-shadow: 0 2px 2px 0 rgba(0, 0, 0, .14), 0 3px 1px -2px rgba(0, 0, 0, .2), 0 1px 5px 0 rgba(0, 0, 0, .12) +} + +.disabled { + background-color: lightgray; + opacity: .6; +} + +/* + * Placeholder dashboard ideas + */ + +.placeholders { + margin-bottom: 150px; + text-align: center; +} +.placeholders h4 { + margin-bottom: 0; +} +.placeholder { + margin-bottom: 20px; +} +.placeholder img { + display: inline-block; + border-radius: 50%; +} + + +/* + * c3.js charts overrides + */ +.c3 line, .c3 path { + stroke: #ccc; +} +.c3-line { + stroke-width: 2px; +} + + +.anim-spin { + animation: spin 2s infinite linear; +} +@keyframes spin { + 0% { + transform: rotate(0deg); + } + 100% { + transform: rotate(359deg); + } +} + +/* + * Animations + */ + +.pulse-border { + animation: pulse 2s infinite; +} + +@keyframes pulse { + 0% { + stroke-width: 3; + opacity: 1; + } + + 10% { + stroke-width: 5; + opacity: 0.2; + } + 15% { + stroke-width: 5; + opacity: 0.2; + } + + 50% { + stroke-width: 3; + opacity: 1; + } + + 100% { + stroke-width: 3; + opacity: 1; + } +} + +/* + * Switch checkbox CSS, originally from: + * https://community.tadabase.io/t/convert-checkbox-to-toggle-switch/2566 + */ + +input[type="checkbox"].switch { + /* Backgrpund properties */ + appearance: none; + background-color: #e1e1e1; /* unchecked background color */ + border-radius: 72px; + border-style: none; + flex-shrink: 0; + position: relative; + cursor: pointer; + margin: 0 !important; + width: 40px !important; + height: 20px !important; + border: 1px solid #ccc; +} +input[type="checkbox"].switch, +input[type="checkbox"].switch::after { + transition: all 100ms ease-out; +} +input[type="checkbox"].switch::after { + /* Ball properties */ + background-color: #fff; /* Color of ball */ + border-radius: 50%; + content: ""; + height: 15px !important; + width: 15px !important; + left: 3px !important; + top: 2px !important; + position: absolute; +} +/* Properties for a checked state */ +input[type="checkbox"].switch:checked { + background-color: #d9534f; /* Color of background */ +} +input[type="checkbox"].switch:checked::after { + background-color: #fff; /* Color of ball */ + left: 20px !important; +} + +/* + * Slider styling + */ + +input[type="range"] { + accent-color: #d9534f; +} diff --git a/resource/web/css/bootstrap-switch.css b/hal-core/resources/web/css/lib/bootstrap-switch.css old mode 100755 new mode 100644 similarity index 84% rename from resource/web/css/bootstrap-switch.css rename to hal-core/resources/web/css/lib/bootstrap-switch.css index 6c0cc1dd..608fc698 --- a/resource/web/css/bootstrap-switch.css +++ b/hal-core/resources/web/css/lib/bootstrap-switch.css @@ -1,23 +1,11 @@ -/* ======================================================================== - * bootstrap-switch - v3.3.2 - * http://www.bootstrap-switch.org - * ======================================================================== - * Copyright 2012-2013 Mattia Larentis - * - * ======================================================================== - * 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. - * ======================================================================== - */ +/** + * bootstrap-switch - Turn checkboxes and radio buttons into toggle switches. + * + * @version v3.3.4 + * @homepage https://bttstrp.github.io/bootstrap-switch + * @author Mattia Larentis (http://larentis.eu) + * @license Apache-2.0 + */ .bootstrap-switch { display: inline-block; @@ -25,7 +13,7 @@ cursor: pointer; border-radius: 4px; border: 1px solid; - border-color: #cccccc; + border-color: #ccc; position: relative; text-align: left; overflow: hidden; @@ -54,8 +42,8 @@ -moz-box-sizing: border-box; box-sizing: border-box; cursor: pointer; - display: inline-block !important; - height: 100%; + display: table-cell; + vertical-align: middle; padding: 6px 12px; font-size: 14px; line-height: 20px; @@ -100,8 +88,11 @@ margin-top: -1px; margin-bottom: -1px; z-index: 100; - color: #333333; - background: #ffffff; + color: #333; + background: #fff; +} +.bootstrap-switch span::before { + content: "\200b"; } .bootstrap-switch .bootstrap-switch-handle-on { border-bottom-left-radius: 3px; @@ -120,6 +111,7 @@ z-index: -1; opacity: 0; filter: alpha(opacity=0); + visibility: hidden; } .bootstrap-switch.bootstrap-switch-mini .bootstrap-switch-handle-on, .bootstrap-switch.bootstrap-switch-mini .bootstrap-switch-handle-off, diff --git a/hal-core/resources/web/css/lib/bootstrap-switch.min.css b/hal-core/resources/web/css/lib/bootstrap-switch.min.css new file mode 100644 index 00000000..77006595 --- /dev/null +++ b/hal-core/resources/web/css/lib/bootstrap-switch.min.css @@ -0,0 +1,10 @@ +/** + * bootstrap-switch - Turn checkboxes and radio buttons into toggle switches. + * + * @version v3.3.4 + * @homepage https://bttstrp.github.io/bootstrap-switch + * @author Mattia Larentis (http://larentis.eu) + * @license Apache-2.0 + */ + +.bootstrap-switch{display:inline-block;direction:ltr;cursor:pointer;border-radius:4px;border:1px solid #ccc;position:relative;text-align:left;overflow:hidden;line-height:8px;z-index:0;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;vertical-align:middle;-webkit-transition:border-color ease-in-out .15s,box-shadow ease-in-out .15s;-o-transition:border-color ease-in-out .15s,box-shadow ease-in-out .15s;transition:border-color ease-in-out .15s,box-shadow ease-in-out .15s}.bootstrap-switch .bootstrap-switch-container{display:inline-block;top:0;border-radius:4px;-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0)}.bootstrap-switch .bootstrap-switch-handle-off,.bootstrap-switch .bootstrap-switch-handle-on,.bootstrap-switch .bootstrap-switch-label{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;cursor:pointer;display:table-cell;vertical-align:middle;padding:6px 12px;font-size:14px;line-height:20px}.bootstrap-switch .bootstrap-switch-handle-off,.bootstrap-switch .bootstrap-switch-handle-on{text-align:center;z-index:1}.bootstrap-switch .bootstrap-switch-handle-off.bootstrap-switch-primary,.bootstrap-switch .bootstrap-switch-handle-on.bootstrap-switch-primary{color:#fff;background:#337ab7}.bootstrap-switch .bootstrap-switch-handle-off.bootstrap-switch-info,.bootstrap-switch .bootstrap-switch-handle-on.bootstrap-switch-info{color:#fff;background:#5bc0de}.bootstrap-switch .bootstrap-switch-handle-off.bootstrap-switch-success,.bootstrap-switch .bootstrap-switch-handle-on.bootstrap-switch-success{color:#fff;background:#5cb85c}.bootstrap-switch .bootstrap-switch-handle-off.bootstrap-switch-warning,.bootstrap-switch .bootstrap-switch-handle-on.bootstrap-switch-warning{background:#f0ad4e;color:#fff}.bootstrap-switch .bootstrap-switch-handle-off.bootstrap-switch-danger,.bootstrap-switch .bootstrap-switch-handle-on.bootstrap-switch-danger{color:#fff;background:#d9534f}.bootstrap-switch .bootstrap-switch-handle-off.bootstrap-switch-default,.bootstrap-switch .bootstrap-switch-handle-on.bootstrap-switch-default{color:#000;background:#eee}.bootstrap-switch .bootstrap-switch-label{text-align:center;margin-top:-1px;margin-bottom:-1px;z-index:100;color:#333;background:#fff}.bootstrap-switch span::before{content:"\200b"}.bootstrap-switch .bootstrap-switch-handle-on{border-bottom-left-radius:3px;border-top-left-radius:3px}.bootstrap-switch .bootstrap-switch-handle-off{border-bottom-right-radius:3px;border-top-right-radius:3px}.bootstrap-switch input[type=radio],.bootstrap-switch input[type=checkbox]{position:absolute!important;top:0;left:0;margin:0;z-index:-1;opacity:0;filter:alpha(opacity=0);visibility:hidden}.bootstrap-switch.bootstrap-switch-mini .bootstrap-switch-handle-off,.bootstrap-switch.bootstrap-switch-mini .bootstrap-switch-handle-on,.bootstrap-switch.bootstrap-switch-mini .bootstrap-switch-label{padding:1px 5px;font-size:12px;line-height:1.5}.bootstrap-switch.bootstrap-switch-small .bootstrap-switch-handle-off,.bootstrap-switch.bootstrap-switch-small .bootstrap-switch-handle-on,.bootstrap-switch.bootstrap-switch-small .bootstrap-switch-label{padding:5px 10px;font-size:12px;line-height:1.5}.bootstrap-switch.bootstrap-switch-large .bootstrap-switch-handle-off,.bootstrap-switch.bootstrap-switch-large .bootstrap-switch-handle-on,.bootstrap-switch.bootstrap-switch-large .bootstrap-switch-label{padding:6px 16px;font-size:18px;line-height:1.3333333}.bootstrap-switch.bootstrap-switch-disabled,.bootstrap-switch.bootstrap-switch-indeterminate,.bootstrap-switch.bootstrap-switch-readonly{cursor:default!important}.bootstrap-switch.bootstrap-switch-disabled .bootstrap-switch-handle-off,.bootstrap-switch.bootstrap-switch-disabled .bootstrap-switch-handle-on,.bootstrap-switch.bootstrap-switch-disabled .bootstrap-switch-label,.bootstrap-switch.bootstrap-switch-indeterminate .bootstrap-switch-handle-off,.bootstrap-switch.bootstrap-switch-indeterminate .bootstrap-switch-handle-on,.bootstrap-switch.bootstrap-switch-indeterminate .bootstrap-switch-label,.bootstrap-switch.bootstrap-switch-readonly .bootstrap-switch-handle-off,.bootstrap-switch.bootstrap-switch-readonly .bootstrap-switch-handle-on,.bootstrap-switch.bootstrap-switch-readonly .bootstrap-switch-label{opacity:.5;filter:alpha(opacity=50);cursor:default!important}.bootstrap-switch.bootstrap-switch-animate .bootstrap-switch-container{-webkit-transition:margin-left .5s;-o-transition:margin-left .5s;transition:margin-left .5s}.bootstrap-switch.bootstrap-switch-inverse .bootstrap-switch-handle-on{border-radius:0 3px 3px 0}.bootstrap-switch.bootstrap-switch-inverse .bootstrap-switch-handle-off{border-radius:3px 0 0 3px}.bootstrap-switch.bootstrap-switch-focused{border-color:#66afe9;outline:0;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 8px rgba(102,175,233,.6);box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 8px rgba(102,175,233,.6)}.bootstrap-switch.bootstrap-switch-inverse.bootstrap-switch-off .bootstrap-switch-label,.bootstrap-switch.bootstrap-switch-on .bootstrap-switch-label{border-bottom-right-radius:3px;border-top-right-radius:3px}.bootstrap-switch.bootstrap-switch-inverse.bootstrap-switch-on .bootstrap-switch-label,.bootstrap-switch.bootstrap-switch-off .bootstrap-switch-label{border-bottom-left-radius:3px;border-top-left-radius:3px} \ No newline at end of file diff --git a/resource/web/css/bootstrap-theme.css b/hal-core/resources/web/css/lib/bootstrap-theme.css old mode 100755 new mode 100644 similarity index 99% rename from resource/web/css/bootstrap-theme.css rename to hal-core/resources/web/css/lib/bootstrap-theme.css index ebe57fbf..31d88826 --- a/resource/web/css/bootstrap-theme.css +++ b/hal-core/resources/web/css/lib/bootstrap-theme.css @@ -1,6 +1,6 @@ /*! - * Bootstrap v3.3.6 (http://getbootstrap.com) - * Copyright 2011-2015 Twitter, Inc. + * Bootstrap v3.3.7 (http://getbootstrap.com) + * Copyright 2011-2016 Twitter, Inc. * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) */ .btn-default, diff --git a/resource/web/css/bootstrap-theme.min.css b/hal-core/resources/web/css/lib/bootstrap-theme.min.css old mode 100755 new mode 100644 similarity index 99% rename from resource/web/css/bootstrap-theme.min.css rename to hal-core/resources/web/css/lib/bootstrap-theme.min.css index dc95d8e4..5e394019 --- a/resource/web/css/bootstrap-theme.min.css +++ b/hal-core/resources/web/css/lib/bootstrap-theme.min.css @@ -1,6 +1,6 @@ /*! - * Bootstrap v3.3.6 (http://getbootstrap.com) - * Copyright 2011-2015 Twitter, Inc. + * Bootstrap v3.3.7 (http://getbootstrap.com) + * Copyright 2011-2016 Twitter, Inc. * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) */.btn-danger,.btn-default,.btn-info,.btn-primary,.btn-success,.btn-warning{text-shadow:0 -1px 0 rgba(0,0,0,.2);-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.15),0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 0 rgba(255,255,255,.15),0 1px 1px rgba(0,0,0,.075)}.btn-danger.active,.btn-danger:active,.btn-default.active,.btn-default:active,.btn-info.active,.btn-info:active,.btn-primary.active,.btn-primary:active,.btn-success.active,.btn-success:active,.btn-warning.active,.btn-warning:active{-webkit-box-shadow:inset 0 3px 5px rgba(0,0,0,.125);box-shadow:inset 0 3px 5px rgba(0,0,0,.125)}.btn-danger.disabled,.btn-danger[disabled],.btn-default.disabled,.btn-default[disabled],.btn-info.disabled,.btn-info[disabled],.btn-primary.disabled,.btn-primary[disabled],.btn-success.disabled,.btn-success[disabled],.btn-warning.disabled,.btn-warning[disabled],fieldset[disabled] .btn-danger,fieldset[disabled] .btn-default,fieldset[disabled] .btn-info,fieldset[disabled] .btn-primary,fieldset[disabled] .btn-success,fieldset[disabled] .btn-warning{-webkit-box-shadow:none;box-shadow:none}.btn-danger .badge,.btn-default .badge,.btn-info .badge,.btn-primary .badge,.btn-success .badge,.btn-warning .badge{text-shadow:none}.btn.active,.btn:active{background-image:none}.btn-default{text-shadow:0 1px 0 #fff;background-image:-webkit-linear-gradient(top,#fff 0,#e0e0e0 100%);background-image:-o-linear-gradient(top,#fff 0,#e0e0e0 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#fff),to(#e0e0e0));background-image:linear-gradient(to bottom,#fff 0,#e0e0e0 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#ffe0e0e0', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-color:#dbdbdb;border-color:#ccc}.btn-default:focus,.btn-default:hover{background-color:#e0e0e0;background-position:0 -15px}.btn-default.active,.btn-default:active{background-color:#e0e0e0;border-color:#dbdbdb}.btn-default.disabled,.btn-default.disabled.active,.btn-default.disabled.focus,.btn-default.disabled:active,.btn-default.disabled:focus,.btn-default.disabled:hover,.btn-default[disabled],.btn-default[disabled].active,.btn-default[disabled].focus,.btn-default[disabled]:active,.btn-default[disabled]:focus,.btn-default[disabled]:hover,fieldset[disabled] .btn-default,fieldset[disabled] .btn-default.active,fieldset[disabled] .btn-default.focus,fieldset[disabled] .btn-default:active,fieldset[disabled] .btn-default:focus,fieldset[disabled] .btn-default:hover{background-color:#e0e0e0;background-image:none}.btn-primary{background-image:-webkit-linear-gradient(top,#337ab7 0,#265a88 100%);background-image:-o-linear-gradient(top,#337ab7 0,#265a88 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#337ab7),to(#265a88));background-image:linear-gradient(to bottom,#337ab7 0,#265a88 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff265a88', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-color:#245580}.btn-primary:focus,.btn-primary:hover{background-color:#265a88;background-position:0 -15px}.btn-primary.active,.btn-primary:active{background-color:#265a88;border-color:#245580}.btn-primary.disabled,.btn-primary.disabled.active,.btn-primary.disabled.focus,.btn-primary.disabled:active,.btn-primary.disabled:focus,.btn-primary.disabled:hover,.btn-primary[disabled],.btn-primary[disabled].active,.btn-primary[disabled].focus,.btn-primary[disabled]:active,.btn-primary[disabled]:focus,.btn-primary[disabled]:hover,fieldset[disabled] .btn-primary,fieldset[disabled] .btn-primary.active,fieldset[disabled] .btn-primary.focus,fieldset[disabled] .btn-primary:active,fieldset[disabled] .btn-primary:focus,fieldset[disabled] .btn-primary:hover{background-color:#265a88;background-image:none}.btn-success{background-image:-webkit-linear-gradient(top,#5cb85c 0,#419641 100%);background-image:-o-linear-gradient(top,#5cb85c 0,#419641 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#5cb85c),to(#419641));background-image:linear-gradient(to bottom,#5cb85c 0,#419641 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5cb85c', endColorstr='#ff419641', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-color:#3e8f3e}.btn-success:focus,.btn-success:hover{background-color:#419641;background-position:0 -15px}.btn-success.active,.btn-success:active{background-color:#419641;border-color:#3e8f3e}.btn-success.disabled,.btn-success.disabled.active,.btn-success.disabled.focus,.btn-success.disabled:active,.btn-success.disabled:focus,.btn-success.disabled:hover,.btn-success[disabled],.btn-success[disabled].active,.btn-success[disabled].focus,.btn-success[disabled]:active,.btn-success[disabled]:focus,.btn-success[disabled]:hover,fieldset[disabled] .btn-success,fieldset[disabled] .btn-success.active,fieldset[disabled] .btn-success.focus,fieldset[disabled] .btn-success:active,fieldset[disabled] .btn-success:focus,fieldset[disabled] .btn-success:hover{background-color:#419641;background-image:none}.btn-info{background-image:-webkit-linear-gradient(top,#5bc0de 0,#2aabd2 100%);background-image:-o-linear-gradient(top,#5bc0de 0,#2aabd2 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#5bc0de),to(#2aabd2));background-image:linear-gradient(to bottom,#5bc0de 0,#2aabd2 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff2aabd2', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-color:#28a4c9}.btn-info:focus,.btn-info:hover{background-color:#2aabd2;background-position:0 -15px}.btn-info.active,.btn-info:active{background-color:#2aabd2;border-color:#28a4c9}.btn-info.disabled,.btn-info.disabled.active,.btn-info.disabled.focus,.btn-info.disabled:active,.btn-info.disabled:focus,.btn-info.disabled:hover,.btn-info[disabled],.btn-info[disabled].active,.btn-info[disabled].focus,.btn-info[disabled]:active,.btn-info[disabled]:focus,.btn-info[disabled]:hover,fieldset[disabled] .btn-info,fieldset[disabled] .btn-info.active,fieldset[disabled] .btn-info.focus,fieldset[disabled] .btn-info:active,fieldset[disabled] .btn-info:focus,fieldset[disabled] .btn-info:hover{background-color:#2aabd2;background-image:none}.btn-warning{background-image:-webkit-linear-gradient(top,#f0ad4e 0,#eb9316 100%);background-image:-o-linear-gradient(top,#f0ad4e 0,#eb9316 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#f0ad4e),to(#eb9316));background-image:linear-gradient(to bottom,#f0ad4e 0,#eb9316 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff0ad4e', endColorstr='#ffeb9316', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-color:#e38d13}.btn-warning:focus,.btn-warning:hover{background-color:#eb9316;background-position:0 -15px}.btn-warning.active,.btn-warning:active{background-color:#eb9316;border-color:#e38d13}.btn-warning.disabled,.btn-warning.disabled.active,.btn-warning.disabled.focus,.btn-warning.disabled:active,.btn-warning.disabled:focus,.btn-warning.disabled:hover,.btn-warning[disabled],.btn-warning[disabled].active,.btn-warning[disabled].focus,.btn-warning[disabled]:active,.btn-warning[disabled]:focus,.btn-warning[disabled]:hover,fieldset[disabled] .btn-warning,fieldset[disabled] .btn-warning.active,fieldset[disabled] .btn-warning.focus,fieldset[disabled] .btn-warning:active,fieldset[disabled] .btn-warning:focus,fieldset[disabled] .btn-warning:hover{background-color:#eb9316;background-image:none}.btn-danger{background-image:-webkit-linear-gradient(top,#d9534f 0,#c12e2a 100%);background-image:-o-linear-gradient(top,#d9534f 0,#c12e2a 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#d9534f),to(#c12e2a));background-image:linear-gradient(to bottom,#d9534f 0,#c12e2a 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9534f', endColorstr='#ffc12e2a', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-color:#b92c28}.btn-danger:focus,.btn-danger:hover{background-color:#c12e2a;background-position:0 -15px}.btn-danger.active,.btn-danger:active{background-color:#c12e2a;border-color:#b92c28}.btn-danger.disabled,.btn-danger.disabled.active,.btn-danger.disabled.focus,.btn-danger.disabled:active,.btn-danger.disabled:focus,.btn-danger.disabled:hover,.btn-danger[disabled],.btn-danger[disabled].active,.btn-danger[disabled].focus,.btn-danger[disabled]:active,.btn-danger[disabled]:focus,.btn-danger[disabled]:hover,fieldset[disabled] .btn-danger,fieldset[disabled] .btn-danger.active,fieldset[disabled] .btn-danger.focus,fieldset[disabled] .btn-danger:active,fieldset[disabled] .btn-danger:focus,fieldset[disabled] .btn-danger:hover{background-color:#c12e2a;background-image:none}.img-thumbnail,.thumbnail{-webkit-box-shadow:0 1px 2px rgba(0,0,0,.075);box-shadow:0 1px 2px rgba(0,0,0,.075)}.dropdown-menu>li>a:focus,.dropdown-menu>li>a:hover{background-color:#e8e8e8;background-image:-webkit-linear-gradient(top,#f5f5f5 0,#e8e8e8 100%);background-image:-o-linear-gradient(top,#f5f5f5 0,#e8e8e8 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#f5f5f5),to(#e8e8e8));background-image:linear-gradient(to bottom,#f5f5f5 0,#e8e8e8 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#ffe8e8e8', GradientType=0);background-repeat:repeat-x}.dropdown-menu>.active>a,.dropdown-menu>.active>a:focus,.dropdown-menu>.active>a:hover{background-color:#2e6da4;background-image:-webkit-linear-gradient(top,#337ab7 0,#2e6da4 100%);background-image:-o-linear-gradient(top,#337ab7 0,#2e6da4 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#337ab7),to(#2e6da4));background-image:linear-gradient(to bottom,#337ab7 0,#2e6da4 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff2e6da4', GradientType=0);background-repeat:repeat-x}.navbar-default{background-image:-webkit-linear-gradient(top,#fff 0,#f8f8f8 100%);background-image:-o-linear-gradient(top,#fff 0,#f8f8f8 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#fff),to(#f8f8f8));background-image:linear-gradient(to bottom,#fff 0,#f8f8f8 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#fff8f8f8', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-radius:4px;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.15),0 1px 5px rgba(0,0,0,.075);box-shadow:inset 0 1px 0 rgba(255,255,255,.15),0 1px 5px rgba(0,0,0,.075)}.navbar-default .navbar-nav>.active>a,.navbar-default .navbar-nav>.open>a{background-image:-webkit-linear-gradient(top,#dbdbdb 0,#e2e2e2 100%);background-image:-o-linear-gradient(top,#dbdbdb 0,#e2e2e2 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#dbdbdb),to(#e2e2e2));background-image:linear-gradient(to bottom,#dbdbdb 0,#e2e2e2 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdbdbdb', endColorstr='#ffe2e2e2', GradientType=0);background-repeat:repeat-x;-webkit-box-shadow:inset 0 3px 9px rgba(0,0,0,.075);box-shadow:inset 0 3px 9px rgba(0,0,0,.075)}.navbar-brand,.navbar-nav>li>a{text-shadow:0 1px 0 rgba(255,255,255,.25)}.navbar-inverse{background-image:-webkit-linear-gradient(top,#3c3c3c 0,#222 100%);background-image:-o-linear-gradient(top,#3c3c3c 0,#222 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#3c3c3c),to(#222));background-image:linear-gradient(to bottom,#3c3c3c 0,#222 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff3c3c3c', endColorstr='#ff222222', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-radius:4px}.navbar-inverse .navbar-nav>.active>a,.navbar-inverse .navbar-nav>.open>a{background-image:-webkit-linear-gradient(top,#080808 0,#0f0f0f 100%);background-image:-o-linear-gradient(top,#080808 0,#0f0f0f 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#080808),to(#0f0f0f));background-image:linear-gradient(to bottom,#080808 0,#0f0f0f 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff080808', endColorstr='#ff0f0f0f', GradientType=0);background-repeat:repeat-x;-webkit-box-shadow:inset 0 3px 9px rgba(0,0,0,.25);box-shadow:inset 0 3px 9px rgba(0,0,0,.25)}.navbar-inverse .navbar-brand,.navbar-inverse .navbar-nav>li>a{text-shadow:0 -1px 0 rgba(0,0,0,.25)}.navbar-fixed-bottom,.navbar-fixed-top,.navbar-static-top{border-radius:0}@media (max-width:767px){.navbar .navbar-nav .open .dropdown-menu>.active>a,.navbar .navbar-nav .open .dropdown-menu>.active>a:focus,.navbar .navbar-nav .open .dropdown-menu>.active>a:hover{color:#fff;background-image:-webkit-linear-gradient(top,#337ab7 0,#2e6da4 100%);background-image:-o-linear-gradient(top,#337ab7 0,#2e6da4 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#337ab7),to(#2e6da4));background-image:linear-gradient(to bottom,#337ab7 0,#2e6da4 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff2e6da4', GradientType=0);background-repeat:repeat-x}}.alert{text-shadow:0 1px 0 rgba(255,255,255,.2);-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.25),0 1px 2px rgba(0,0,0,.05);box-shadow:inset 0 1px 0 rgba(255,255,255,.25),0 1px 2px rgba(0,0,0,.05)}.alert-success{background-image:-webkit-linear-gradient(top,#dff0d8 0,#c8e5bc 100%);background-image:-o-linear-gradient(top,#dff0d8 0,#c8e5bc 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#dff0d8),to(#c8e5bc));background-image:linear-gradient(to bottom,#dff0d8 0,#c8e5bc 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdff0d8', endColorstr='#ffc8e5bc', GradientType=0);background-repeat:repeat-x;border-color:#b2dba1}.alert-info{background-image:-webkit-linear-gradient(top,#d9edf7 0,#b9def0 100%);background-image:-o-linear-gradient(top,#d9edf7 0,#b9def0 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#d9edf7),to(#b9def0));background-image:linear-gradient(to bottom,#d9edf7 0,#b9def0 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9edf7', endColorstr='#ffb9def0', GradientType=0);background-repeat:repeat-x;border-color:#9acfea}.alert-warning{background-image:-webkit-linear-gradient(top,#fcf8e3 0,#f8efc0 100%);background-image:-o-linear-gradient(top,#fcf8e3 0,#f8efc0 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#fcf8e3),to(#f8efc0));background-image:linear-gradient(to bottom,#fcf8e3 0,#f8efc0 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffcf8e3', endColorstr='#fff8efc0', GradientType=0);background-repeat:repeat-x;border-color:#f5e79e}.alert-danger{background-image:-webkit-linear-gradient(top,#f2dede 0,#e7c3c3 100%);background-image:-o-linear-gradient(top,#f2dede 0,#e7c3c3 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#f2dede),to(#e7c3c3));background-image:linear-gradient(to bottom,#f2dede 0,#e7c3c3 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2dede', endColorstr='#ffe7c3c3', GradientType=0);background-repeat:repeat-x;border-color:#dca7a7}.progress{background-image:-webkit-linear-gradient(top,#ebebeb 0,#f5f5f5 100%);background-image:-o-linear-gradient(top,#ebebeb 0,#f5f5f5 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#ebebeb),to(#f5f5f5));background-image:linear-gradient(to bottom,#ebebeb 0,#f5f5f5 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffebebeb', endColorstr='#fff5f5f5', GradientType=0);background-repeat:repeat-x}.progress-bar{background-image:-webkit-linear-gradient(top,#337ab7 0,#286090 100%);background-image:-o-linear-gradient(top,#337ab7 0,#286090 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#337ab7),to(#286090));background-image:linear-gradient(to bottom,#337ab7 0,#286090 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff286090', GradientType=0);background-repeat:repeat-x}.progress-bar-success{background-image:-webkit-linear-gradient(top,#5cb85c 0,#449d44 100%);background-image:-o-linear-gradient(top,#5cb85c 0,#449d44 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#5cb85c),to(#449d44));background-image:linear-gradient(to bottom,#5cb85c 0,#449d44 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5cb85c', endColorstr='#ff449d44', GradientType=0);background-repeat:repeat-x}.progress-bar-info{background-image:-webkit-linear-gradient(top,#5bc0de 0,#31b0d5 100%);background-image:-o-linear-gradient(top,#5bc0de 0,#31b0d5 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#5bc0de),to(#31b0d5));background-image:linear-gradient(to bottom,#5bc0de 0,#31b0d5 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff31b0d5', GradientType=0);background-repeat:repeat-x}.progress-bar-warning{background-image:-webkit-linear-gradient(top,#f0ad4e 0,#ec971f 100%);background-image:-o-linear-gradient(top,#f0ad4e 0,#ec971f 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#f0ad4e),to(#ec971f));background-image:linear-gradient(to bottom,#f0ad4e 0,#ec971f 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff0ad4e', endColorstr='#ffec971f', GradientType=0);background-repeat:repeat-x}.progress-bar-danger{background-image:-webkit-linear-gradient(top,#d9534f 0,#c9302c 100%);background-image:-o-linear-gradient(top,#d9534f 0,#c9302c 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#d9534f),to(#c9302c));background-image:linear-gradient(to bottom,#d9534f 0,#c9302c 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9534f', endColorstr='#ffc9302c', GradientType=0);background-repeat:repeat-x}.progress-bar-striped{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)}.list-group{border-radius:4px;-webkit-box-shadow:0 1px 2px rgba(0,0,0,.075);box-shadow:0 1px 2px rgba(0,0,0,.075)}.list-group-item.active,.list-group-item.active:focus,.list-group-item.active:hover{text-shadow:0 -1px 0 #286090;background-image:-webkit-linear-gradient(top,#337ab7 0,#2b669a 100%);background-image:-o-linear-gradient(top,#337ab7 0,#2b669a 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#337ab7),to(#2b669a));background-image:linear-gradient(to bottom,#337ab7 0,#2b669a 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff2b669a', GradientType=0);background-repeat:repeat-x;border-color:#2b669a}.list-group-item.active .badge,.list-group-item.active:focus .badge,.list-group-item.active:hover .badge{text-shadow:none}.panel{-webkit-box-shadow:0 1px 2px rgba(0,0,0,.05);box-shadow:0 1px 2px rgba(0,0,0,.05)}.panel-default>.panel-heading{background-image:-webkit-linear-gradient(top,#f5f5f5 0,#e8e8e8 100%);background-image:-o-linear-gradient(top,#f5f5f5 0,#e8e8e8 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#f5f5f5),to(#e8e8e8));background-image:linear-gradient(to bottom,#f5f5f5 0,#e8e8e8 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#ffe8e8e8', GradientType=0);background-repeat:repeat-x}.panel-primary>.panel-heading{background-image:-webkit-linear-gradient(top,#337ab7 0,#2e6da4 100%);background-image:-o-linear-gradient(top,#337ab7 0,#2e6da4 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#337ab7),to(#2e6da4));background-image:linear-gradient(to bottom,#337ab7 0,#2e6da4 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff2e6da4', GradientType=0);background-repeat:repeat-x}.panel-success>.panel-heading{background-image:-webkit-linear-gradient(top,#dff0d8 0,#d0e9c6 100%);background-image:-o-linear-gradient(top,#dff0d8 0,#d0e9c6 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#dff0d8),to(#d0e9c6));background-image:linear-gradient(to bottom,#dff0d8 0,#d0e9c6 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdff0d8', endColorstr='#ffd0e9c6', GradientType=0);background-repeat:repeat-x}.panel-info>.panel-heading{background-image:-webkit-linear-gradient(top,#d9edf7 0,#c4e3f3 100%);background-image:-o-linear-gradient(top,#d9edf7 0,#c4e3f3 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#d9edf7),to(#c4e3f3));background-image:linear-gradient(to bottom,#d9edf7 0,#c4e3f3 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9edf7', endColorstr='#ffc4e3f3', GradientType=0);background-repeat:repeat-x}.panel-warning>.panel-heading{background-image:-webkit-linear-gradient(top,#fcf8e3 0,#faf2cc 100%);background-image:-o-linear-gradient(top,#fcf8e3 0,#faf2cc 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#fcf8e3),to(#faf2cc));background-image:linear-gradient(to bottom,#fcf8e3 0,#faf2cc 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffcf8e3', endColorstr='#fffaf2cc', GradientType=0);background-repeat:repeat-x}.panel-danger>.panel-heading{background-image:-webkit-linear-gradient(top,#f2dede 0,#ebcccc 100%);background-image:-o-linear-gradient(top,#f2dede 0,#ebcccc 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#f2dede),to(#ebcccc));background-image:linear-gradient(to bottom,#f2dede 0,#ebcccc 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2dede', endColorstr='#ffebcccc', GradientType=0);background-repeat:repeat-x}.well{background-image:-webkit-linear-gradient(top,#e8e8e8 0,#f5f5f5 100%);background-image:-o-linear-gradient(top,#e8e8e8 0,#f5f5f5 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#e8e8e8),to(#f5f5f5));background-image:linear-gradient(to bottom,#e8e8e8 0,#f5f5f5 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffe8e8e8', endColorstr='#fff5f5f5', GradientType=0);background-repeat:repeat-x;border-color:#dcdcdc;-webkit-box-shadow:inset 0 1px 3px rgba(0,0,0,.05),0 1px 0 rgba(255,255,255,.1);box-shadow:inset 0 1px 3px rgba(0,0,0,.05),0 1px 0 rgba(255,255,255,.1)} /*# sourceMappingURL=bootstrap-theme.min.css.map */ \ No newline at end of file diff --git a/resource/web/css/bootstrap.css b/hal-core/resources/web/css/lib/bootstrap.css old mode 100755 new mode 100644 similarity index 99% rename from resource/web/css/bootstrap.css rename to hal-core/resources/web/css/lib/bootstrap.css index 42c79d6e..8176de13 --- a/resource/web/css/bootstrap.css +++ b/hal-core/resources/web/css/lib/bootstrap.css @@ -1,6 +1,6 @@ /*! - * Bootstrap v3.3.6 (http://getbootstrap.com) - * Copyright 2011-2015 Twitter, Inc. + * Bootstrap v3.3.7 (http://getbootstrap.com) + * Copyright 2011-2016 Twitter, Inc. * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) */ /*! normalize.css v3.0.3 | MIT License | github.com/necolas/normalize.css */ @@ -263,8 +263,8 @@ th { @font-face { font-family: 'Glyphicons Halflings'; - src: url('../fonts/glyphicons-halflings-regular.eot'); - src: url('../fonts/glyphicons-halflings-regular.eot?#iefix') format('embedded-opentype'), url('../fonts/glyphicons-halflings-regular.woff2') format('woff2'), url('../fonts/glyphicons-halflings-regular.woff') format('woff'), url('../fonts/glyphicons-halflings-regular.ttf') format('truetype'), url('../fonts/glyphicons-halflings-regular.svg#glyphicons_halflingsregular') format('svg'); + src: url('../../fonts/glyphicons-halflings-regular.eot'); + src: url('../../fonts/glyphicons-halflings-regular.eot?#iefix') format('embedded-opentype'), url('../../fonts/glyphicons-halflings-regular.woff2') format('woff2'), url('../../fonts/glyphicons-halflings-regular.woff') format('woff'), url('../../fonts/glyphicons-halflings-regular.ttf') format('truetype'), url('../../fonts/glyphicons-halflings-regular.svg#glyphicons_halflingsregular') format('svg'); } .glyphicon { position: relative; @@ -1106,7 +1106,6 @@ a:focus { text-decoration: underline; } a:focus { - outline: thin dotted; outline: 5px auto -webkit-focus-ring-color; outline-offset: -2px; } @@ -2537,7 +2536,6 @@ select[size] { input[type="file"]:focus, input[type="radio"]:focus, input[type="checkbox"]:focus { - outline: thin dotted; outline: 5px auto -webkit-focus-ring-color; outline-offset: -2px; } @@ -3029,7 +3027,6 @@ select[multiple].input-lg { .btn.focus, .btn:active.focus, .btn.active.focus { - outline: thin dotted; outline: 5px auto -webkit-focus-ring-color; outline-offset: -2px; } diff --git a/hal-core/resources/web/css/lib/bootstrap.min.css b/hal-core/resources/web/css/lib/bootstrap.min.css new file mode 100644 index 00000000..2b8fc88d --- /dev/null +++ b/hal-core/resources/web/css/lib/bootstrap.min.css @@ -0,0 +1,6 @@ +/*! + * Bootstrap v3.3.7 (http://getbootstrap.com) + * Copyright 2011-2016 Twitter, Inc. + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) + *//*! normalize.css v3.0.3 | MIT License | github.com/necolas/normalize.css */html{font-family:sans-serif;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%}body{margin:0}article,aside,details,figcaption,figure,footer,header,hgroup,main,menu,nav,section,summary{display:block}audio,canvas,progress,video{display:inline-block;vertical-align:baseline}audio:not([controls]){display:none;height:0}[hidden],template{display:none}a{background-color:transparent}a:active,a:hover{outline:0}abbr[title]{border-bottom:1px dotted}b,strong{font-weight:700}dfn{font-style:italic}h1{margin:.67em 0;font-size:2em}mark{color:#000;background:#ff0}small{font-size:80%}sub,sup{position:relative;font-size:75%;line-height:0;vertical-align:baseline}sup{top:-.5em}sub{bottom:-.25em}img{border:0}svg:not(:root){overflow:hidden}figure{margin:1em 40px}hr{height:0;-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box}pre{overflow:auto}code,kbd,pre,samp{font-family:monospace,monospace;font-size:1em}button,input,optgroup,select,textarea{margin:0;font:inherit;color:inherit}button{overflow:visible}button,select{text-transform:none}button,html input[type=button],input[type=reset],input[type=submit]{-webkit-appearance:button;cursor:pointer}button[disabled],html input[disabled]{cursor:default}button::-moz-focus-inner,input::-moz-focus-inner{padding:0;border:0}input{line-height:normal}input[type=checkbox],input[type=radio]{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;padding:0}input[type=number]::-webkit-inner-spin-button,input[type=number]::-webkit-outer-spin-button{height:auto}input[type=search]{-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box;-webkit-appearance:textfield}input[type=search]::-webkit-search-cancel-button,input[type=search]::-webkit-search-decoration{-webkit-appearance:none}fieldset{padding:.35em .625em .75em;margin:0 2px;border:1px solid silver}legend{padding:0;border:0}textarea{overflow:auto}optgroup{font-weight:700}table{border-spacing:0;border-collapse:collapse}td,th{padding:0}/*! Source: https://github.com/h5bp/html5-boilerplate/blob/master/src/css/main.css */@media print{*,:after,:before{color:#000!important;text-shadow:none!important;background:0 0!important;-webkit-box-shadow:none!important;box-shadow:none!important}a,a:visited{text-decoration:underline}a[href]:after{content:" (" attr(href) ")"}abbr[title]:after{content:" (" attr(title) ")"}a[href^="javascript:"]:after,a[href^="#"]:after{content:""}blockquote,pre{border:1px solid #999;page-break-inside:avoid}thead{display:table-header-group}img,tr{page-break-inside:avoid}img{max-width:100%!important}h2,h3,p{orphans:3;widows:3}h2,h3{page-break-after:avoid}.navbar{display:none}.btn>.caret,.dropup>.btn>.caret{border-top-color:#000!important}.label{border:1px solid #000}.table{border-collapse:collapse!important}.table td,.table th{background-color:#fff!important}.table-bordered td,.table-bordered th{border:1px solid #ddd!important}}@font-face{font-family:'Glyphicons Halflings';src:url(../../fonts/glyphicons-halflings-regular.eot);src:url(../../fonts/glyphicons-halflings-regular.eot?#iefix) format('embedded-opentype'),url(../../fonts/glyphicons-halflings-regular.woff2) format('woff2'),url(../../fonts/glyphicons-halflings-regular.woff) format('woff'),url(../../fonts/glyphicons-halflings-regular.ttf) format('truetype'),url(../../fonts/glyphicons-halflings-regular.svg#glyphicons_halflingsregular) format('svg')}.glyphicon{position:relative;top:1px;display:inline-block;font-family:'Glyphicons Halflings';font-style:normal;font-weight:400;line-height:1;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.glyphicon-asterisk:before{content:"\002a"}.glyphicon-plus:before{content:"\002b"}.glyphicon-eur:before,.glyphicon-euro:before{content:"\20ac"}.glyphicon-minus:before{content:"\2212"}.glyphicon-cloud:before{content:"\2601"}.glyphicon-envelope:before{content:"\2709"}.glyphicon-pencil:before{content:"\270f"}.glyphicon-glass:before{content:"\e001"}.glyphicon-music:before{content:"\e002"}.glyphicon-search:before{content:"\e003"}.glyphicon-heart:before{content:"\e005"}.glyphicon-star:before{content:"\e006"}.glyphicon-star-empty:before{content:"\e007"}.glyphicon-user:before{content:"\e008"}.glyphicon-film:before{content:"\e009"}.glyphicon-th-large:before{content:"\e010"}.glyphicon-th:before{content:"\e011"}.glyphicon-th-list:before{content:"\e012"}.glyphicon-ok:before{content:"\e013"}.glyphicon-remove:before{content:"\e014"}.glyphicon-zoom-in:before{content:"\e015"}.glyphicon-zoom-out:before{content:"\e016"}.glyphicon-off:before{content:"\e017"}.glyphicon-signal:before{content:"\e018"}.glyphicon-cog:before{content:"\e019"}.glyphicon-trash:before{content:"\e020"}.glyphicon-home:before{content:"\e021"}.glyphicon-file:before{content:"\e022"}.glyphicon-time:before{content:"\e023"}.glyphicon-road:before{content:"\e024"}.glyphicon-download-alt:before{content:"\e025"}.glyphicon-download:before{content:"\e026"}.glyphicon-upload:before{content:"\e027"}.glyphicon-inbox:before{content:"\e028"}.glyphicon-play-circle:before{content:"\e029"}.glyphicon-repeat:before{content:"\e030"}.glyphicon-refresh:before{content:"\e031"}.glyphicon-list-alt:before{content:"\e032"}.glyphicon-lock:before{content:"\e033"}.glyphicon-flag:before{content:"\e034"}.glyphicon-headphones:before{content:"\e035"}.glyphicon-volume-off:before{content:"\e036"}.glyphicon-volume-down:before{content:"\e037"}.glyphicon-volume-up:before{content:"\e038"}.glyphicon-qrcode:before{content:"\e039"}.glyphicon-barcode:before{content:"\e040"}.glyphicon-tag:before{content:"\e041"}.glyphicon-tags:before{content:"\e042"}.glyphicon-book:before{content:"\e043"}.glyphicon-bookmark:before{content:"\e044"}.glyphicon-print:before{content:"\e045"}.glyphicon-camera:before{content:"\e046"}.glyphicon-font:before{content:"\e047"}.glyphicon-bold:before{content:"\e048"}.glyphicon-italic:before{content:"\e049"}.glyphicon-text-height:before{content:"\e050"}.glyphicon-text-width:before{content:"\e051"}.glyphicon-align-left:before{content:"\e052"}.glyphicon-align-center:before{content:"\e053"}.glyphicon-align-right:before{content:"\e054"}.glyphicon-align-justify:before{content:"\e055"}.glyphicon-list:before{content:"\e056"}.glyphicon-indent-left:before{content:"\e057"}.glyphicon-indent-right:before{content:"\e058"}.glyphicon-facetime-video:before{content:"\e059"}.glyphicon-picture:before{content:"\e060"}.glyphicon-map-marker:before{content:"\e062"}.glyphicon-adjust:before{content:"\e063"}.glyphicon-tint:before{content:"\e064"}.glyphicon-edit:before{content:"\e065"}.glyphicon-share:before{content:"\e066"}.glyphicon-check:before{content:"\e067"}.glyphicon-move:before{content:"\e068"}.glyphicon-step-backward:before{content:"\e069"}.glyphicon-fast-backward:before{content:"\e070"}.glyphicon-backward:before{content:"\e071"}.glyphicon-play:before{content:"\e072"}.glyphicon-pause:before{content:"\e073"}.glyphicon-stop:before{content:"\e074"}.glyphicon-forward:before{content:"\e075"}.glyphicon-fast-forward:before{content:"\e076"}.glyphicon-step-forward:before{content:"\e077"}.glyphicon-eject:before{content:"\e078"}.glyphicon-chevron-left:before{content:"\e079"}.glyphicon-chevron-right:before{content:"\e080"}.glyphicon-plus-sign:before{content:"\e081"}.glyphicon-minus-sign:before{content:"\e082"}.glyphicon-remove-sign:before{content:"\e083"}.glyphicon-ok-sign:before{content:"\e084"}.glyphicon-question-sign:before{content:"\e085"}.glyphicon-info-sign:before{content:"\e086"}.glyphicon-screenshot:before{content:"\e087"}.glyphicon-remove-circle:before{content:"\e088"}.glyphicon-ok-circle:before{content:"\e089"}.glyphicon-ban-circle:before{content:"\e090"}.glyphicon-arrow-left:before{content:"\e091"}.glyphicon-arrow-right:before{content:"\e092"}.glyphicon-arrow-up:before{content:"\e093"}.glyphicon-arrow-down:before{content:"\e094"}.glyphicon-share-alt:before{content:"\e095"}.glyphicon-resize-full:before{content:"\e096"}.glyphicon-resize-small:before{content:"\e097"}.glyphicon-exclamation-sign:before{content:"\e101"}.glyphicon-gift:before{content:"\e102"}.glyphicon-leaf:before{content:"\e103"}.glyphicon-fire:before{content:"\e104"}.glyphicon-eye-open:before{content:"\e105"}.glyphicon-eye-close:before{content:"\e106"}.glyphicon-warning-sign:before{content:"\e107"}.glyphicon-plane:before{content:"\e108"}.glyphicon-calendar:before{content:"\e109"}.glyphicon-random:before{content:"\e110"}.glyphicon-comment:before{content:"\e111"}.glyphicon-magnet:before{content:"\e112"}.glyphicon-chevron-up:before{content:"\e113"}.glyphicon-chevron-down:before{content:"\e114"}.glyphicon-retweet:before{content:"\e115"}.glyphicon-shopping-cart:before{content:"\e116"}.glyphicon-folder-close:before{content:"\e117"}.glyphicon-folder-open:before{content:"\e118"}.glyphicon-resize-vertical:before{content:"\e119"}.glyphicon-resize-horizontal:before{content:"\e120"}.glyphicon-hdd:before{content:"\e121"}.glyphicon-bullhorn:before{content:"\e122"}.glyphicon-bell:before{content:"\e123"}.glyphicon-certificate:before{content:"\e124"}.glyphicon-thumbs-up:before{content:"\e125"}.glyphicon-thumbs-down:before{content:"\e126"}.glyphicon-hand-right:before{content:"\e127"}.glyphicon-hand-left:before{content:"\e128"}.glyphicon-hand-up:before{content:"\e129"}.glyphicon-hand-down:before{content:"\e130"}.glyphicon-circle-arrow-right:before{content:"\e131"}.glyphicon-circle-arrow-left:before{content:"\e132"}.glyphicon-circle-arrow-up:before{content:"\e133"}.glyphicon-circle-arrow-down:before{content:"\e134"}.glyphicon-globe:before{content:"\e135"}.glyphicon-wrench:before{content:"\e136"}.glyphicon-tasks:before{content:"\e137"}.glyphicon-filter:before{content:"\e138"}.glyphicon-briefcase:before{content:"\e139"}.glyphicon-fullscreen:before{content:"\e140"}.glyphicon-dashboard:before{content:"\e141"}.glyphicon-paperclip:before{content:"\e142"}.glyphicon-heart-empty:before{content:"\e143"}.glyphicon-link:before{content:"\e144"}.glyphicon-phone:before{content:"\e145"}.glyphicon-pushpin:before{content:"\e146"}.glyphicon-usd:before{content:"\e148"}.glyphicon-gbp:before{content:"\e149"}.glyphicon-sort:before{content:"\e150"}.glyphicon-sort-by-alphabet:before{content:"\e151"}.glyphicon-sort-by-alphabet-alt:before{content:"\e152"}.glyphicon-sort-by-order:before{content:"\e153"}.glyphicon-sort-by-order-alt:before{content:"\e154"}.glyphicon-sort-by-attributes:before{content:"\e155"}.glyphicon-sort-by-attributes-alt:before{content:"\e156"}.glyphicon-unchecked:before{content:"\e157"}.glyphicon-expand:before{content:"\e158"}.glyphicon-collapse-down:before{content:"\e159"}.glyphicon-collapse-up:before{content:"\e160"}.glyphicon-log-in:before{content:"\e161"}.glyphicon-flash:before{content:"\e162"}.glyphicon-log-out:before{content:"\e163"}.glyphicon-new-window:before{content:"\e164"}.glyphicon-record:before{content:"\e165"}.glyphicon-save:before{content:"\e166"}.glyphicon-open:before{content:"\e167"}.glyphicon-saved:before{content:"\e168"}.glyphicon-import:before{content:"\e169"}.glyphicon-export:before{content:"\e170"}.glyphicon-send:before{content:"\e171"}.glyphicon-floppy-disk:before{content:"\e172"}.glyphicon-floppy-saved:before{content:"\e173"}.glyphicon-floppy-remove:before{content:"\e174"}.glyphicon-floppy-save:before{content:"\e175"}.glyphicon-floppy-open:before{content:"\e176"}.glyphicon-credit-card:before{content:"\e177"}.glyphicon-transfer:before{content:"\e178"}.glyphicon-cutlery:before{content:"\e179"}.glyphicon-header:before{content:"\e180"}.glyphicon-compressed:before{content:"\e181"}.glyphicon-earphone:before{content:"\e182"}.glyphicon-phone-alt:before{content:"\e183"}.glyphicon-tower:before{content:"\e184"}.glyphicon-stats:before{content:"\e185"}.glyphicon-sd-video:before{content:"\e186"}.glyphicon-hd-video:before{content:"\e187"}.glyphicon-subtitles:before{content:"\e188"}.glyphicon-sound-stereo:before{content:"\e189"}.glyphicon-sound-dolby:before{content:"\e190"}.glyphicon-sound-5-1:before{content:"\e191"}.glyphicon-sound-6-1:before{content:"\e192"}.glyphicon-sound-7-1:before{content:"\e193"}.glyphicon-copyright-mark:before{content:"\e194"}.glyphicon-registration-mark:before{content:"\e195"}.glyphicon-cloud-download:before{content:"\e197"}.glyphicon-cloud-upload:before{content:"\e198"}.glyphicon-tree-conifer:before{content:"\e199"}.glyphicon-tree-deciduous:before{content:"\e200"}.glyphicon-cd:before{content:"\e201"}.glyphicon-save-file:before{content:"\e202"}.glyphicon-open-file:before{content:"\e203"}.glyphicon-level-up:before{content:"\e204"}.glyphicon-copy:before{content:"\e205"}.glyphicon-paste:before{content:"\e206"}.glyphicon-alert:before{content:"\e209"}.glyphicon-equalizer:before{content:"\e210"}.glyphicon-king:before{content:"\e211"}.glyphicon-queen:before{content:"\e212"}.glyphicon-pawn:before{content:"\e213"}.glyphicon-bishop:before{content:"\e214"}.glyphicon-knight:before{content:"\e215"}.glyphicon-baby-formula:before{content:"\e216"}.glyphicon-tent:before{content:"\26fa"}.glyphicon-blackboard:before{content:"\e218"}.glyphicon-bed:before{content:"\e219"}.glyphicon-apple:before{content:"\f8ff"}.glyphicon-erase:before{content:"\e221"}.glyphicon-hourglass:before{content:"\231b"}.glyphicon-lamp:before{content:"\e223"}.glyphicon-duplicate:before{content:"\e224"}.glyphicon-piggy-bank:before{content:"\e225"}.glyphicon-scissors:before{content:"\e226"}.glyphicon-bitcoin:before{content:"\e227"}.glyphicon-btc:before{content:"\e227"}.glyphicon-xbt:before{content:"\e227"}.glyphicon-yen:before{content:"\00a5"}.glyphicon-jpy:before{content:"\00a5"}.glyphicon-ruble:before{content:"\20bd"}.glyphicon-rub:before{content:"\20bd"}.glyphicon-scale:before{content:"\e230"}.glyphicon-ice-lolly:before{content:"\e231"}.glyphicon-ice-lolly-tasted:before{content:"\e232"}.glyphicon-education:before{content:"\e233"}.glyphicon-option-horizontal:before{content:"\e234"}.glyphicon-option-vertical:before{content:"\e235"}.glyphicon-menu-hamburger:before{content:"\e236"}.glyphicon-modal-window:before{content:"\e237"}.glyphicon-oil:before{content:"\e238"}.glyphicon-grain:before{content:"\e239"}.glyphicon-sunglasses:before{content:"\e240"}.glyphicon-text-size:before{content:"\e241"}.glyphicon-text-color:before{content:"\e242"}.glyphicon-text-background:before{content:"\e243"}.glyphicon-object-align-top:before{content:"\e244"}.glyphicon-object-align-bottom:before{content:"\e245"}.glyphicon-object-align-horizontal:before{content:"\e246"}.glyphicon-object-align-left:before{content:"\e247"}.glyphicon-object-align-vertical:before{content:"\e248"}.glyphicon-object-align-right:before{content:"\e249"}.glyphicon-triangle-right:before{content:"\e250"}.glyphicon-triangle-left:before{content:"\e251"}.glyphicon-triangle-bottom:before{content:"\e252"}.glyphicon-triangle-top:before{content:"\e253"}.glyphicon-console:before{content:"\e254"}.glyphicon-superscript:before{content:"\e255"}.glyphicon-subscript:before{content:"\e256"}.glyphicon-menu-left:before{content:"\e257"}.glyphicon-menu-right:before{content:"\e258"}.glyphicon-menu-down:before{content:"\e259"}.glyphicon-menu-up:before{content:"\e260"}*{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}:after,:before{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}html{font-size:10px;-webkit-tap-highlight-color:rgba(0,0,0,0)}body{font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:14px;line-height:1.42857143;color:#333;background-color:#fff}button,input,select,textarea{font-family:inherit;font-size:inherit;line-height:inherit}a{color:#337ab7;text-decoration:none}a:focus,a:hover{color:#23527c;text-decoration:underline}a:focus{outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}figure{margin:0}img{vertical-align:middle}.carousel-inner>.item>a>img,.carousel-inner>.item>img,.img-responsive,.thumbnail a>img,.thumbnail>img{display:block;max-width:100%;height:auto}.img-rounded{border-radius:6px}.img-thumbnail{display:inline-block;max-width:100%;height:auto;padding:4px;line-height:1.42857143;background-color:#fff;border:1px solid #ddd;border-radius:4px;-webkit-transition:all .2s ease-in-out;-o-transition:all .2s ease-in-out;transition:all .2s ease-in-out}.img-circle{border-radius:50%}hr{margin-top:20px;margin-bottom:20px;border:0;border-top:1px solid #eee}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);border:0}.sr-only-focusable:active,.sr-only-focusable:focus{position:static;width:auto;height:auto;margin:0;overflow:visible;clip:auto}[role=button]{cursor:pointer}.h1,.h2,.h3,.h4,.h5,.h6,h1,h2,h3,h4,h5,h6{font-family:inherit;font-weight:500;line-height:1.1;color:inherit}.h1 .small,.h1 small,.h2 .small,.h2 small,.h3 .small,.h3 small,.h4 .small,.h4 small,.h5 .small,.h5 small,.h6 .small,.h6 small,h1 .small,h1 small,h2 .small,h2 small,h3 .small,h3 small,h4 .small,h4 small,h5 .small,h5 small,h6 .small,h6 small{font-weight:400;line-height:1;color:#777}.h1,.h2,.h3,h1,h2,h3{margin-top:20px;margin-bottom:10px}.h1 .small,.h1 small,.h2 .small,.h2 small,.h3 .small,.h3 small,h1 .small,h1 small,h2 .small,h2 small,h3 .small,h3 small{font-size:65%}.h4,.h5,.h6,h4,h5,h6{margin-top:10px;margin-bottom:10px}.h4 .small,.h4 small,.h5 .small,.h5 small,.h6 .small,.h6 small,h4 .small,h4 small,h5 .small,h5 small,h6 .small,h6 small{font-size:75%}.h1,h1{font-size:36px}.h2,h2{font-size:30px}.h3,h3{font-size:24px}.h4,h4{font-size:18px}.h5,h5{font-size:14px}.h6,h6{font-size:12px}p{margin:0 0 10px}.lead{margin-bottom:20px;font-size:16px;font-weight:300;line-height:1.4}@media (min-width:768px){.lead{font-size:21px}}.small,small{font-size:85%}.mark,mark{padding:.2em;background-color:#fcf8e3}.text-left{text-align:left}.text-right{text-align:right}.text-center{text-align:center}.text-justify{text-align:justify}.text-nowrap{white-space:nowrap}.text-lowercase{text-transform:lowercase}.text-uppercase{text-transform:uppercase}.text-capitalize{text-transform:capitalize}.text-muted{color:#777}.text-primary{color:#337ab7}a.text-primary:focus,a.text-primary:hover{color:#286090}.text-success{color:#3c763d}a.text-success:focus,a.text-success:hover{color:#2b542c}.text-info{color:#31708f}a.text-info:focus,a.text-info:hover{color:#245269}.text-warning{color:#8a6d3b}a.text-warning:focus,a.text-warning:hover{color:#66512c}.text-danger{color:#a94442}a.text-danger:focus,a.text-danger:hover{color:#843534}.bg-primary{color:#fff;background-color:#337ab7}a.bg-primary:focus,a.bg-primary:hover{background-color:#286090}.bg-success{background-color:#dff0d8}a.bg-success:focus,a.bg-success:hover{background-color:#c1e2b3}.bg-info{background-color:#d9edf7}a.bg-info:focus,a.bg-info:hover{background-color:#afd9ee}.bg-warning{background-color:#fcf8e3}a.bg-warning:focus,a.bg-warning:hover{background-color:#f7ecb5}.bg-danger{background-color:#f2dede}a.bg-danger:focus,a.bg-danger:hover{background-color:#e4b9b9}.page-header{padding-bottom:9px;margin:40px 0 20px;border-bottom:1px solid #eee}ol,ul{margin-top:0;margin-bottom:10px}ol ol,ol ul,ul ol,ul ul{margin-bottom:0}.list-unstyled{padding-left:0;list-style:none}.list-inline{padding-left:0;margin-left:-5px;list-style:none}.list-inline>li{display:inline-block;padding-right:5px;padding-left:5px}dl{margin-top:0;margin-bottom:20px}dd,dt{line-height:1.42857143}dt{font-weight:700}dd{margin-left:0}@media (min-width:768px){.dl-horizontal dt{float:left;width:160px;overflow:hidden;clear:left;text-align:right;text-overflow:ellipsis;white-space:nowrap}.dl-horizontal dd{margin-left:180px}}abbr[data-original-title],abbr[title]{cursor:help;border-bottom:1px dotted #777}.initialism{font-size:90%;text-transform:uppercase}blockquote{padding:10px 20px;margin:0 0 20px;font-size:17.5px;border-left:5px solid #eee}blockquote ol:last-child,blockquote p:last-child,blockquote ul:last-child{margin-bottom:0}blockquote .small,blockquote footer,blockquote small{display:block;font-size:80%;line-height:1.42857143;color:#777}blockquote .small:before,blockquote footer:before,blockquote small:before{content:'\2014 \00A0'}.blockquote-reverse,blockquote.pull-right{padding-right:15px;padding-left:0;text-align:right;border-right:5px solid #eee;border-left:0}.blockquote-reverse .small:before,.blockquote-reverse footer:before,.blockquote-reverse small:before,blockquote.pull-right .small:before,blockquote.pull-right footer:before,blockquote.pull-right small:before{content:''}.blockquote-reverse .small:after,.blockquote-reverse footer:after,.blockquote-reverse small:after,blockquote.pull-right .small:after,blockquote.pull-right footer:after,blockquote.pull-right small:after{content:'\00A0 \2014'}address{margin-bottom:20px;font-style:normal;line-height:1.42857143}code,kbd,pre,samp{font-family:Menlo,Monaco,Consolas,"Courier New",monospace}code{padding:2px 4px;font-size:90%;color:#c7254e;background-color:#f9f2f4;border-radius:4px}kbd{padding:2px 4px;font-size:90%;color:#fff;background-color:#333;border-radius:3px;-webkit-box-shadow:inset 0 -1px 0 rgba(0,0,0,.25);box-shadow:inset 0 -1px 0 rgba(0,0,0,.25)}kbd kbd{padding:0;font-size:100%;font-weight:700;-webkit-box-shadow:none;box-shadow:none}pre{display:block;padding:9.5px;margin:0 0 10px;font-size:13px;line-height:1.42857143;color:#333;word-break:break-all;word-wrap:break-word;background-color:#f5f5f5;border:1px solid #ccc;border-radius:4px}pre code{padding:0;font-size:inherit;color:inherit;white-space:pre-wrap;background-color:transparent;border-radius:0}.pre-scrollable{max-height:340px;overflow-y:scroll}.container{padding-right:15px;padding-left:15px;margin-right:auto;margin-left:auto}@media (min-width:768px){.container{width:750px}}@media (min-width:992px){.container{width:970px}}@media (min-width:1200px){.container{width:1170px}}.container-fluid{padding-right:15px;padding-left:15px;margin-right:auto;margin-left:auto}.row{margin-right:-15px;margin-left:-15px}.col-lg-1,.col-lg-10,.col-lg-11,.col-lg-12,.col-lg-2,.col-lg-3,.col-lg-4,.col-lg-5,.col-lg-6,.col-lg-7,.col-lg-8,.col-lg-9,.col-md-1,.col-md-10,.col-md-11,.col-md-12,.col-md-2,.col-md-3,.col-md-4,.col-md-5,.col-md-6,.col-md-7,.col-md-8,.col-md-9,.col-sm-1,.col-sm-10,.col-sm-11,.col-sm-12,.col-sm-2,.col-sm-3,.col-sm-4,.col-sm-5,.col-sm-6,.col-sm-7,.col-sm-8,.col-sm-9,.col-xs-1,.col-xs-10,.col-xs-11,.col-xs-12,.col-xs-2,.col-xs-3,.col-xs-4,.col-xs-5,.col-xs-6,.col-xs-7,.col-xs-8,.col-xs-9{position:relative;min-height:1px;padding-right:15px;padding-left:15px}.col-xs-1,.col-xs-10,.col-xs-11,.col-xs-12,.col-xs-2,.col-xs-3,.col-xs-4,.col-xs-5,.col-xs-6,.col-xs-7,.col-xs-8,.col-xs-9{float:left}.col-xs-12{width:100%}.col-xs-11{width:91.66666667%}.col-xs-10{width:83.33333333%}.col-xs-9{width:75%}.col-xs-8{width:66.66666667%}.col-xs-7{width:58.33333333%}.col-xs-6{width:50%}.col-xs-5{width:41.66666667%}.col-xs-4{width:33.33333333%}.col-xs-3{width:25%}.col-xs-2{width:16.66666667%}.col-xs-1{width:8.33333333%}.col-xs-pull-12{right:100%}.col-xs-pull-11{right:91.66666667%}.col-xs-pull-10{right:83.33333333%}.col-xs-pull-9{right:75%}.col-xs-pull-8{right:66.66666667%}.col-xs-pull-7{right:58.33333333%}.col-xs-pull-6{right:50%}.col-xs-pull-5{right:41.66666667%}.col-xs-pull-4{right:33.33333333%}.col-xs-pull-3{right:25%}.col-xs-pull-2{right:16.66666667%}.col-xs-pull-1{right:8.33333333%}.col-xs-pull-0{right:auto}.col-xs-push-12{left:100%}.col-xs-push-11{left:91.66666667%}.col-xs-push-10{left:83.33333333%}.col-xs-push-9{left:75%}.col-xs-push-8{left:66.66666667%}.col-xs-push-7{left:58.33333333%}.col-xs-push-6{left:50%}.col-xs-push-5{left:41.66666667%}.col-xs-push-4{left:33.33333333%}.col-xs-push-3{left:25%}.col-xs-push-2{left:16.66666667%}.col-xs-push-1{left:8.33333333%}.col-xs-push-0{left:auto}.col-xs-offset-12{margin-left:100%}.col-xs-offset-11{margin-left:91.66666667%}.col-xs-offset-10{margin-left:83.33333333%}.col-xs-offset-9{margin-left:75%}.col-xs-offset-8{margin-left:66.66666667%}.col-xs-offset-7{margin-left:58.33333333%}.col-xs-offset-6{margin-left:50%}.col-xs-offset-5{margin-left:41.66666667%}.col-xs-offset-4{margin-left:33.33333333%}.col-xs-offset-3{margin-left:25%}.col-xs-offset-2{margin-left:16.66666667%}.col-xs-offset-1{margin-left:8.33333333%}.col-xs-offset-0{margin-left:0}@media (min-width:768px){.col-sm-1,.col-sm-10,.col-sm-11,.col-sm-12,.col-sm-2,.col-sm-3,.col-sm-4,.col-sm-5,.col-sm-6,.col-sm-7,.col-sm-8,.col-sm-9{float:left}.col-sm-12{width:100%}.col-sm-11{width:91.66666667%}.col-sm-10{width:83.33333333%}.col-sm-9{width:75%}.col-sm-8{width:66.66666667%}.col-sm-7{width:58.33333333%}.col-sm-6{width:50%}.col-sm-5{width:41.66666667%}.col-sm-4{width:33.33333333%}.col-sm-3{width:25%}.col-sm-2{width:16.66666667%}.col-sm-1{width:8.33333333%}.col-sm-pull-12{right:100%}.col-sm-pull-11{right:91.66666667%}.col-sm-pull-10{right:83.33333333%}.col-sm-pull-9{right:75%}.col-sm-pull-8{right:66.66666667%}.col-sm-pull-7{right:58.33333333%}.col-sm-pull-6{right:50%}.col-sm-pull-5{right:41.66666667%}.col-sm-pull-4{right:33.33333333%}.col-sm-pull-3{right:25%}.col-sm-pull-2{right:16.66666667%}.col-sm-pull-1{right:8.33333333%}.col-sm-pull-0{right:auto}.col-sm-push-12{left:100%}.col-sm-push-11{left:91.66666667%}.col-sm-push-10{left:83.33333333%}.col-sm-push-9{left:75%}.col-sm-push-8{left:66.66666667%}.col-sm-push-7{left:58.33333333%}.col-sm-push-6{left:50%}.col-sm-push-5{left:41.66666667%}.col-sm-push-4{left:33.33333333%}.col-sm-push-3{left:25%}.col-sm-push-2{left:16.66666667%}.col-sm-push-1{left:8.33333333%}.col-sm-push-0{left:auto}.col-sm-offset-12{margin-left:100%}.col-sm-offset-11{margin-left:91.66666667%}.col-sm-offset-10{margin-left:83.33333333%}.col-sm-offset-9{margin-left:75%}.col-sm-offset-8{margin-left:66.66666667%}.col-sm-offset-7{margin-left:58.33333333%}.col-sm-offset-6{margin-left:50%}.col-sm-offset-5{margin-left:41.66666667%}.col-sm-offset-4{margin-left:33.33333333%}.col-sm-offset-3{margin-left:25%}.col-sm-offset-2{margin-left:16.66666667%}.col-sm-offset-1{margin-left:8.33333333%}.col-sm-offset-0{margin-left:0}}@media (min-width:992px){.col-md-1,.col-md-10,.col-md-11,.col-md-12,.col-md-2,.col-md-3,.col-md-4,.col-md-5,.col-md-6,.col-md-7,.col-md-8,.col-md-9{float:left}.col-md-12{width:100%}.col-md-11{width:91.66666667%}.col-md-10{width:83.33333333%}.col-md-9{width:75%}.col-md-8{width:66.66666667%}.col-md-7{width:58.33333333%}.col-md-6{width:50%}.col-md-5{width:41.66666667%}.col-md-4{width:33.33333333%}.col-md-3{width:25%}.col-md-2{width:16.66666667%}.col-md-1{width:8.33333333%}.col-md-pull-12{right:100%}.col-md-pull-11{right:91.66666667%}.col-md-pull-10{right:83.33333333%}.col-md-pull-9{right:75%}.col-md-pull-8{right:66.66666667%}.col-md-pull-7{right:58.33333333%}.col-md-pull-6{right:50%}.col-md-pull-5{right:41.66666667%}.col-md-pull-4{right:33.33333333%}.col-md-pull-3{right:25%}.col-md-pull-2{right:16.66666667%}.col-md-pull-1{right:8.33333333%}.col-md-pull-0{right:auto}.col-md-push-12{left:100%}.col-md-push-11{left:91.66666667%}.col-md-push-10{left:83.33333333%}.col-md-push-9{left:75%}.col-md-push-8{left:66.66666667%}.col-md-push-7{left:58.33333333%}.col-md-push-6{left:50%}.col-md-push-5{left:41.66666667%}.col-md-push-4{left:33.33333333%}.col-md-push-3{left:25%}.col-md-push-2{left:16.66666667%}.col-md-push-1{left:8.33333333%}.col-md-push-0{left:auto}.col-md-offset-12{margin-left:100%}.col-md-offset-11{margin-left:91.66666667%}.col-md-offset-10{margin-left:83.33333333%}.col-md-offset-9{margin-left:75%}.col-md-offset-8{margin-left:66.66666667%}.col-md-offset-7{margin-left:58.33333333%}.col-md-offset-6{margin-left:50%}.col-md-offset-5{margin-left:41.66666667%}.col-md-offset-4{margin-left:33.33333333%}.col-md-offset-3{margin-left:25%}.col-md-offset-2{margin-left:16.66666667%}.col-md-offset-1{margin-left:8.33333333%}.col-md-offset-0{margin-left:0}}@media (min-width:1200px){.col-lg-1,.col-lg-10,.col-lg-11,.col-lg-12,.col-lg-2,.col-lg-3,.col-lg-4,.col-lg-5,.col-lg-6,.col-lg-7,.col-lg-8,.col-lg-9{float:left}.col-lg-12{width:100%}.col-lg-11{width:91.66666667%}.col-lg-10{width:83.33333333%}.col-lg-9{width:75%}.col-lg-8{width:66.66666667%}.col-lg-7{width:58.33333333%}.col-lg-6{width:50%}.col-lg-5{width:41.66666667%}.col-lg-4{width:33.33333333%}.col-lg-3{width:25%}.col-lg-2{width:16.66666667%}.col-lg-1{width:8.33333333%}.col-lg-pull-12{right:100%}.col-lg-pull-11{right:91.66666667%}.col-lg-pull-10{right:83.33333333%}.col-lg-pull-9{right:75%}.col-lg-pull-8{right:66.66666667%}.col-lg-pull-7{right:58.33333333%}.col-lg-pull-6{right:50%}.col-lg-pull-5{right:41.66666667%}.col-lg-pull-4{right:33.33333333%}.col-lg-pull-3{right:25%}.col-lg-pull-2{right:16.66666667%}.col-lg-pull-1{right:8.33333333%}.col-lg-pull-0{right:auto}.col-lg-push-12{left:100%}.col-lg-push-11{left:91.66666667%}.col-lg-push-10{left:83.33333333%}.col-lg-push-9{left:75%}.col-lg-push-8{left:66.66666667%}.col-lg-push-7{left:58.33333333%}.col-lg-push-6{left:50%}.col-lg-push-5{left:41.66666667%}.col-lg-push-4{left:33.33333333%}.col-lg-push-3{left:25%}.col-lg-push-2{left:16.66666667%}.col-lg-push-1{left:8.33333333%}.col-lg-push-0{left:auto}.col-lg-offset-12{margin-left:100%}.col-lg-offset-11{margin-left:91.66666667%}.col-lg-offset-10{margin-left:83.33333333%}.col-lg-offset-9{margin-left:75%}.col-lg-offset-8{margin-left:66.66666667%}.col-lg-offset-7{margin-left:58.33333333%}.col-lg-offset-6{margin-left:50%}.col-lg-offset-5{margin-left:41.66666667%}.col-lg-offset-4{margin-left:33.33333333%}.col-lg-offset-3{margin-left:25%}.col-lg-offset-2{margin-left:16.66666667%}.col-lg-offset-1{margin-left:8.33333333%}.col-lg-offset-0{margin-left:0}}table{background-color:transparent}caption{padding-top:8px;padding-bottom:8px;color:#777;text-align:left}th{text-align:left}.table{width:100%;max-width:100%;margin-bottom:20px}.table>tbody>tr>td,.table>tbody>tr>th,.table>tfoot>tr>td,.table>tfoot>tr>th,.table>thead>tr>td,.table>thead>tr>th{padding:8px;line-height:1.42857143;vertical-align:top;border-top:1px solid #ddd}.table>thead>tr>th{vertical-align:bottom;border-bottom:2px solid #ddd}.table>caption+thead>tr:first-child>td,.table>caption+thead>tr:first-child>th,.table>colgroup+thead>tr:first-child>td,.table>colgroup+thead>tr:first-child>th,.table>thead:first-child>tr:first-child>td,.table>thead:first-child>tr:first-child>th{border-top:0}.table>tbody+tbody{border-top:2px solid #ddd}.table .table{background-color:#fff}.table-condensed>tbody>tr>td,.table-condensed>tbody>tr>th,.table-condensed>tfoot>tr>td,.table-condensed>tfoot>tr>th,.table-condensed>thead>tr>td,.table-condensed>thead>tr>th{padding:5px}.table-bordered{border:1px solid #ddd}.table-bordered>tbody>tr>td,.table-bordered>tbody>tr>th,.table-bordered>tfoot>tr>td,.table-bordered>tfoot>tr>th,.table-bordered>thead>tr>td,.table-bordered>thead>tr>th{border:1px solid #ddd}.table-bordered>thead>tr>td,.table-bordered>thead>tr>th{border-bottom-width:2px}.table-striped>tbody>tr:nth-of-type(odd){background-color:#f9f9f9}.table-hover>tbody>tr:hover{background-color:#f5f5f5}table col[class*=col-]{position:static;display:table-column;float:none}table td[class*=col-],table th[class*=col-]{position:static;display:table-cell;float:none}.table>tbody>tr.active>td,.table>tbody>tr.active>th,.table>tbody>tr>td.active,.table>tbody>tr>th.active,.table>tfoot>tr.active>td,.table>tfoot>tr.active>th,.table>tfoot>tr>td.active,.table>tfoot>tr>th.active,.table>thead>tr.active>td,.table>thead>tr.active>th,.table>thead>tr>td.active,.table>thead>tr>th.active{background-color:#f5f5f5}.table-hover>tbody>tr.active:hover>td,.table-hover>tbody>tr.active:hover>th,.table-hover>tbody>tr:hover>.active,.table-hover>tbody>tr>td.active:hover,.table-hover>tbody>tr>th.active:hover{background-color:#e8e8e8}.table>tbody>tr.success>td,.table>tbody>tr.success>th,.table>tbody>tr>td.success,.table>tbody>tr>th.success,.table>tfoot>tr.success>td,.table>tfoot>tr.success>th,.table>tfoot>tr>td.success,.table>tfoot>tr>th.success,.table>thead>tr.success>td,.table>thead>tr.success>th,.table>thead>tr>td.success,.table>thead>tr>th.success{background-color:#dff0d8}.table-hover>tbody>tr.success:hover>td,.table-hover>tbody>tr.success:hover>th,.table-hover>tbody>tr:hover>.success,.table-hover>tbody>tr>td.success:hover,.table-hover>tbody>tr>th.success:hover{background-color:#d0e9c6}.table>tbody>tr.info>td,.table>tbody>tr.info>th,.table>tbody>tr>td.info,.table>tbody>tr>th.info,.table>tfoot>tr.info>td,.table>tfoot>tr.info>th,.table>tfoot>tr>td.info,.table>tfoot>tr>th.info,.table>thead>tr.info>td,.table>thead>tr.info>th,.table>thead>tr>td.info,.table>thead>tr>th.info{background-color:#d9edf7}.table-hover>tbody>tr.info:hover>td,.table-hover>tbody>tr.info:hover>th,.table-hover>tbody>tr:hover>.info,.table-hover>tbody>tr>td.info:hover,.table-hover>tbody>tr>th.info:hover{background-color:#c4e3f3}.table>tbody>tr.warning>td,.table>tbody>tr.warning>th,.table>tbody>tr>td.warning,.table>tbody>tr>th.warning,.table>tfoot>tr.warning>td,.table>tfoot>tr.warning>th,.table>tfoot>tr>td.warning,.table>tfoot>tr>th.warning,.table>thead>tr.warning>td,.table>thead>tr.warning>th,.table>thead>tr>td.warning,.table>thead>tr>th.warning{background-color:#fcf8e3}.table-hover>tbody>tr.warning:hover>td,.table-hover>tbody>tr.warning:hover>th,.table-hover>tbody>tr:hover>.warning,.table-hover>tbody>tr>td.warning:hover,.table-hover>tbody>tr>th.warning:hover{background-color:#faf2cc}.table>tbody>tr.danger>td,.table>tbody>tr.danger>th,.table>tbody>tr>td.danger,.table>tbody>tr>th.danger,.table>tfoot>tr.danger>td,.table>tfoot>tr.danger>th,.table>tfoot>tr>td.danger,.table>tfoot>tr>th.danger,.table>thead>tr.danger>td,.table>thead>tr.danger>th,.table>thead>tr>td.danger,.table>thead>tr>th.danger{background-color:#f2dede}.table-hover>tbody>tr.danger:hover>td,.table-hover>tbody>tr.danger:hover>th,.table-hover>tbody>tr:hover>.danger,.table-hover>tbody>tr>td.danger:hover,.table-hover>tbody>tr>th.danger:hover{background-color:#ebcccc}.table-responsive{min-height:.01%;overflow-x:auto}@media screen and (max-width:767px){.table-responsive{width:100%;margin-bottom:15px;overflow-y:hidden;-ms-overflow-style:-ms-autohiding-scrollbar;border:1px solid #ddd}.table-responsive>.table{margin-bottom:0}.table-responsive>.table>tbody>tr>td,.table-responsive>.table>tbody>tr>th,.table-responsive>.table>tfoot>tr>td,.table-responsive>.table>tfoot>tr>th,.table-responsive>.table>thead>tr>td,.table-responsive>.table>thead>tr>th{white-space:nowrap}.table-responsive>.table-bordered{border:0}.table-responsive>.table-bordered>tbody>tr>td:first-child,.table-responsive>.table-bordered>tbody>tr>th:first-child,.table-responsive>.table-bordered>tfoot>tr>td:first-child,.table-responsive>.table-bordered>tfoot>tr>th:first-child,.table-responsive>.table-bordered>thead>tr>td:first-child,.table-responsive>.table-bordered>thead>tr>th:first-child{border-left:0}.table-responsive>.table-bordered>tbody>tr>td:last-child,.table-responsive>.table-bordered>tbody>tr>th:last-child,.table-responsive>.table-bordered>tfoot>tr>td:last-child,.table-responsive>.table-bordered>tfoot>tr>th:last-child,.table-responsive>.table-bordered>thead>tr>td:last-child,.table-responsive>.table-bordered>thead>tr>th:last-child{border-right:0}.table-responsive>.table-bordered>tbody>tr:last-child>td,.table-responsive>.table-bordered>tbody>tr:last-child>th,.table-responsive>.table-bordered>tfoot>tr:last-child>td,.table-responsive>.table-bordered>tfoot>tr:last-child>th{border-bottom:0}}fieldset{min-width:0;padding:0;margin:0;border:0}legend{display:block;width:100%;padding:0;margin-bottom:20px;font-size:21px;line-height:inherit;color:#333;border:0;border-bottom:1px solid #e5e5e5}label{display:inline-block;max-width:100%;margin-bottom:5px;font-weight:700}input[type=search]{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}input[type=checkbox],input[type=radio]{margin:4px 0 0;margin-top:1px\9;line-height:normal}input[type=file]{display:block}input[type=range]{display:block;width:100%}select[multiple],select[size]{height:auto}input[type=file]:focus,input[type=checkbox]:focus,input[type=radio]:focus{outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}output{display:block;padding-top:7px;font-size:14px;line-height:1.42857143;color:#555}.form-control{display:block;width:100%;height:34px;padding:6px 12px;font-size:14px;line-height:1.42857143;color:#555;background-color:#fff;background-image:none;border:1px solid #ccc;border-radius:4px;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 1px rgba(0,0,0,.075);-webkit-transition:border-color ease-in-out .15s,-webkit-box-shadow ease-in-out .15s;-o-transition:border-color ease-in-out .15s,box-shadow ease-in-out .15s;transition:border-color ease-in-out .15s,box-shadow ease-in-out .15s}.form-control:focus{border-color:#66afe9;outline:0;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 8px rgba(102,175,233,.6);box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 8px rgba(102,175,233,.6)}.form-control::-moz-placeholder{color:#999;opacity:1}.form-control:-ms-input-placeholder{color:#999}.form-control::-webkit-input-placeholder{color:#999}.form-control::-ms-expand{background-color:transparent;border:0}.form-control[disabled],.form-control[readonly],fieldset[disabled] .form-control{background-color:#eee;opacity:1}.form-control[disabled],fieldset[disabled] .form-control{cursor:not-allowed}textarea.form-control{height:auto}input[type=search]{-webkit-appearance:none}@media screen and (-webkit-min-device-pixel-ratio:0){input[type=date].form-control,input[type=time].form-control,input[type=datetime-local].form-control,input[type=month].form-control{line-height:34px}.input-group-sm input[type=date],.input-group-sm input[type=time],.input-group-sm input[type=datetime-local],.input-group-sm input[type=month],input[type=date].input-sm,input[type=time].input-sm,input[type=datetime-local].input-sm,input[type=month].input-sm{line-height:30px}.input-group-lg input[type=date],.input-group-lg input[type=time],.input-group-lg input[type=datetime-local],.input-group-lg input[type=month],input[type=date].input-lg,input[type=time].input-lg,input[type=datetime-local].input-lg,input[type=month].input-lg{line-height:46px}}.form-group{margin-bottom:15px}.checkbox,.radio{position:relative;display:block;margin-top:10px;margin-bottom:10px}.checkbox label,.radio label{min-height:20px;padding-left:20px;margin-bottom:0;font-weight:400;cursor:pointer}.checkbox input[type=checkbox],.checkbox-inline input[type=checkbox],.radio input[type=radio],.radio-inline input[type=radio]{position:absolute;margin-top:4px\9;margin-left:-20px}.checkbox+.checkbox,.radio+.radio{margin-top:-5px}.checkbox-inline,.radio-inline{position:relative;display:inline-block;padding-left:20px;margin-bottom:0;font-weight:400;vertical-align:middle;cursor:pointer}.checkbox-inline+.checkbox-inline,.radio-inline+.radio-inline{margin-top:0;margin-left:10px}fieldset[disabled] input[type=checkbox],fieldset[disabled] input[type=radio],input[type=checkbox].disabled,input[type=checkbox][disabled],input[type=radio].disabled,input[type=radio][disabled]{cursor:not-allowed}.checkbox-inline.disabled,.radio-inline.disabled,fieldset[disabled] .checkbox-inline,fieldset[disabled] .radio-inline{cursor:not-allowed}.checkbox.disabled label,.radio.disabled label,fieldset[disabled] .checkbox label,fieldset[disabled] .radio label{cursor:not-allowed}.form-control-static{min-height:34px;padding-top:7px;padding-bottom:7px;margin-bottom:0}.form-control-static.input-lg,.form-control-static.input-sm{padding-right:0;padding-left:0}.input-sm{height:30px;padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}select.input-sm{height:30px;line-height:30px}select[multiple].input-sm,textarea.input-sm{height:auto}.form-group-sm .form-control{height:30px;padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}.form-group-sm select.form-control{height:30px;line-height:30px}.form-group-sm select[multiple].form-control,.form-group-sm textarea.form-control{height:auto}.form-group-sm .form-control-static{height:30px;min-height:32px;padding:6px 10px;font-size:12px;line-height:1.5}.input-lg{height:46px;padding:10px 16px;font-size:18px;line-height:1.3333333;border-radius:6px}select.input-lg{height:46px;line-height:46px}select[multiple].input-lg,textarea.input-lg{height:auto}.form-group-lg .form-control{height:46px;padding:10px 16px;font-size:18px;line-height:1.3333333;border-radius:6px}.form-group-lg select.form-control{height:46px;line-height:46px}.form-group-lg select[multiple].form-control,.form-group-lg textarea.form-control{height:auto}.form-group-lg .form-control-static{height:46px;min-height:38px;padding:11px 16px;font-size:18px;line-height:1.3333333}.has-feedback{position:relative}.has-feedback .form-control{padding-right:42.5px}.form-control-feedback{position:absolute;top:0;right:0;z-index:2;display:block;width:34px;height:34px;line-height:34px;text-align:center;pointer-events:none}.form-group-lg .form-control+.form-control-feedback,.input-group-lg+.form-control-feedback,.input-lg+.form-control-feedback{width:46px;height:46px;line-height:46px}.form-group-sm .form-control+.form-control-feedback,.input-group-sm+.form-control-feedback,.input-sm+.form-control-feedback{width:30px;height:30px;line-height:30px}.has-success .checkbox,.has-success .checkbox-inline,.has-success .control-label,.has-success .help-block,.has-success .radio,.has-success .radio-inline,.has-success.checkbox label,.has-success.checkbox-inline label,.has-success.radio label,.has-success.radio-inline label{color:#3c763d}.has-success .form-control{border-color:#3c763d;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 1px rgba(0,0,0,.075)}.has-success .form-control:focus{border-color:#2b542c;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #67b168;box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #67b168}.has-success .input-group-addon{color:#3c763d;background-color:#dff0d8;border-color:#3c763d}.has-success .form-control-feedback{color:#3c763d}.has-warning .checkbox,.has-warning .checkbox-inline,.has-warning .control-label,.has-warning .help-block,.has-warning .radio,.has-warning .radio-inline,.has-warning.checkbox label,.has-warning.checkbox-inline label,.has-warning.radio label,.has-warning.radio-inline label{color:#8a6d3b}.has-warning .form-control{border-color:#8a6d3b;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 1px rgba(0,0,0,.075)}.has-warning .form-control:focus{border-color:#66512c;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #c0a16b;box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #c0a16b}.has-warning .input-group-addon{color:#8a6d3b;background-color:#fcf8e3;border-color:#8a6d3b}.has-warning .form-control-feedback{color:#8a6d3b}.has-error .checkbox,.has-error .checkbox-inline,.has-error .control-label,.has-error .help-block,.has-error .radio,.has-error .radio-inline,.has-error.checkbox label,.has-error.checkbox-inline label,.has-error.radio label,.has-error.radio-inline label{color:#a94442}.has-error .form-control{border-color:#a94442;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 1px rgba(0,0,0,.075)}.has-error .form-control:focus{border-color:#843534;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #ce8483;box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #ce8483}.has-error .input-group-addon{color:#a94442;background-color:#f2dede;border-color:#a94442}.has-error .form-control-feedback{color:#a94442}.has-feedback label~.form-control-feedback{top:25px}.has-feedback label.sr-only~.form-control-feedback{top:0}.help-block{display:block;margin-top:5px;margin-bottom:10px;color:#737373}@media (min-width:768px){.form-inline .form-group{display:inline-block;margin-bottom:0;vertical-align:middle}.form-inline .form-control{display:inline-block;width:auto;vertical-align:middle}.form-inline .form-control-static{display:inline-block}.form-inline .input-group{display:inline-table;vertical-align:middle}.form-inline .input-group .form-control,.form-inline .input-group .input-group-addon,.form-inline .input-group .input-group-btn{width:auto}.form-inline .input-group>.form-control{width:100%}.form-inline .control-label{margin-bottom:0;vertical-align:middle}.form-inline .checkbox,.form-inline .radio{display:inline-block;margin-top:0;margin-bottom:0;vertical-align:middle}.form-inline .checkbox label,.form-inline .radio label{padding-left:0}.form-inline .checkbox input[type=checkbox],.form-inline .radio input[type=radio]{position:relative;margin-left:0}.form-inline .has-feedback .form-control-feedback{top:0}}.form-horizontal .checkbox,.form-horizontal .checkbox-inline,.form-horizontal .radio,.form-horizontal .radio-inline{padding-top:7px;margin-top:0;margin-bottom:0}.form-horizontal .checkbox,.form-horizontal .radio{min-height:27px}.form-horizontal .form-group{margin-right:-15px;margin-left:-15px}@media (min-width:768px){.form-horizontal .control-label{padding-top:7px;margin-bottom:0;text-align:right}}.form-horizontal .has-feedback .form-control-feedback{right:15px}@media (min-width:768px){.form-horizontal .form-group-lg .control-label{padding-top:11px;font-size:18px}}@media (min-width:768px){.form-horizontal .form-group-sm .control-label{padding-top:6px;font-size:12px}}.btn{display:inline-block;padding:6px 12px;margin-bottom:0;font-size:14px;font-weight:400;line-height:1.42857143;text-align:center;white-space:nowrap;vertical-align:middle;-ms-touch-action:manipulation;touch-action:manipulation;cursor:pointer;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;background-image:none;border:1px solid transparent;border-radius:4px}.btn.active.focus,.btn.active:focus,.btn.focus,.btn:active.focus,.btn:active:focus,.btn:focus{outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}.btn.focus,.btn:focus,.btn:hover{color:#333;text-decoration:none}.btn.active,.btn:active{background-image:none;outline:0;-webkit-box-shadow:inset 0 3px 5px rgba(0,0,0,.125);box-shadow:inset 0 3px 5px rgba(0,0,0,.125)}.btn.disabled,.btn[disabled],fieldset[disabled] .btn{cursor:not-allowed;filter:alpha(opacity=65);-webkit-box-shadow:none;box-shadow:none;opacity:.65}a.btn.disabled,fieldset[disabled] a.btn{pointer-events:none}.btn-default{color:#333;background-color:#fff;border-color:#ccc}.btn-default.focus,.btn-default:focus{color:#333;background-color:#e6e6e6;border-color:#8c8c8c}.btn-default:hover{color:#333;background-color:#e6e6e6;border-color:#adadad}.btn-default.active,.btn-default:active,.open>.dropdown-toggle.btn-default{color:#333;background-color:#e6e6e6;border-color:#adadad}.btn-default.active.focus,.btn-default.active:focus,.btn-default.active:hover,.btn-default:active.focus,.btn-default:active:focus,.btn-default:active:hover,.open>.dropdown-toggle.btn-default.focus,.open>.dropdown-toggle.btn-default:focus,.open>.dropdown-toggle.btn-default:hover{color:#333;background-color:#d4d4d4;border-color:#8c8c8c}.btn-default.active,.btn-default:active,.open>.dropdown-toggle.btn-default{background-image:none}.btn-default.disabled.focus,.btn-default.disabled:focus,.btn-default.disabled:hover,.btn-default[disabled].focus,.btn-default[disabled]:focus,.btn-default[disabled]:hover,fieldset[disabled] .btn-default.focus,fieldset[disabled] .btn-default:focus,fieldset[disabled] .btn-default:hover{background-color:#fff;border-color:#ccc}.btn-default .badge{color:#fff;background-color:#333}.btn-primary{color:#fff;background-color:#337ab7;border-color:#2e6da4}.btn-primary.focus,.btn-primary:focus{color:#fff;background-color:#286090;border-color:#122b40}.btn-primary:hover{color:#fff;background-color:#286090;border-color:#204d74}.btn-primary.active,.btn-primary:active,.open>.dropdown-toggle.btn-primary{color:#fff;background-color:#286090;border-color:#204d74}.btn-primary.active.focus,.btn-primary.active:focus,.btn-primary.active:hover,.btn-primary:active.focus,.btn-primary:active:focus,.btn-primary:active:hover,.open>.dropdown-toggle.btn-primary.focus,.open>.dropdown-toggle.btn-primary:focus,.open>.dropdown-toggle.btn-primary:hover{color:#fff;background-color:#204d74;border-color:#122b40}.btn-primary.active,.btn-primary:active,.open>.dropdown-toggle.btn-primary{background-image:none}.btn-primary.disabled.focus,.btn-primary.disabled:focus,.btn-primary.disabled:hover,.btn-primary[disabled].focus,.btn-primary[disabled]:focus,.btn-primary[disabled]:hover,fieldset[disabled] .btn-primary.focus,fieldset[disabled] .btn-primary:focus,fieldset[disabled] .btn-primary:hover{background-color:#337ab7;border-color:#2e6da4}.btn-primary .badge{color:#337ab7;background-color:#fff}.btn-success{color:#fff;background-color:#5cb85c;border-color:#4cae4c}.btn-success.focus,.btn-success:focus{color:#fff;background-color:#449d44;border-color:#255625}.btn-success:hover{color:#fff;background-color:#449d44;border-color:#398439}.btn-success.active,.btn-success:active,.open>.dropdown-toggle.btn-success{color:#fff;background-color:#449d44;border-color:#398439}.btn-success.active.focus,.btn-success.active:focus,.btn-success.active:hover,.btn-success:active.focus,.btn-success:active:focus,.btn-success:active:hover,.open>.dropdown-toggle.btn-success.focus,.open>.dropdown-toggle.btn-success:focus,.open>.dropdown-toggle.btn-success:hover{color:#fff;background-color:#398439;border-color:#255625}.btn-success.active,.btn-success:active,.open>.dropdown-toggle.btn-success{background-image:none}.btn-success.disabled.focus,.btn-success.disabled:focus,.btn-success.disabled:hover,.btn-success[disabled].focus,.btn-success[disabled]:focus,.btn-success[disabled]:hover,fieldset[disabled] .btn-success.focus,fieldset[disabled] .btn-success:focus,fieldset[disabled] .btn-success:hover{background-color:#5cb85c;border-color:#4cae4c}.btn-success .badge{color:#5cb85c;background-color:#fff}.btn-info{color:#fff;background-color:#5bc0de;border-color:#46b8da}.btn-info.focus,.btn-info:focus{color:#fff;background-color:#31b0d5;border-color:#1b6d85}.btn-info:hover{color:#fff;background-color:#31b0d5;border-color:#269abc}.btn-info.active,.btn-info:active,.open>.dropdown-toggle.btn-info{color:#fff;background-color:#31b0d5;border-color:#269abc}.btn-info.active.focus,.btn-info.active:focus,.btn-info.active:hover,.btn-info:active.focus,.btn-info:active:focus,.btn-info:active:hover,.open>.dropdown-toggle.btn-info.focus,.open>.dropdown-toggle.btn-info:focus,.open>.dropdown-toggle.btn-info:hover{color:#fff;background-color:#269abc;border-color:#1b6d85}.btn-info.active,.btn-info:active,.open>.dropdown-toggle.btn-info{background-image:none}.btn-info.disabled.focus,.btn-info.disabled:focus,.btn-info.disabled:hover,.btn-info[disabled].focus,.btn-info[disabled]:focus,.btn-info[disabled]:hover,fieldset[disabled] .btn-info.focus,fieldset[disabled] .btn-info:focus,fieldset[disabled] .btn-info:hover{background-color:#5bc0de;border-color:#46b8da}.btn-info .badge{color:#5bc0de;background-color:#fff}.btn-warning{color:#fff;background-color:#f0ad4e;border-color:#eea236}.btn-warning.focus,.btn-warning:focus{color:#fff;background-color:#ec971f;border-color:#985f0d}.btn-warning:hover{color:#fff;background-color:#ec971f;border-color:#d58512}.btn-warning.active,.btn-warning:active,.open>.dropdown-toggle.btn-warning{color:#fff;background-color:#ec971f;border-color:#d58512}.btn-warning.active.focus,.btn-warning.active:focus,.btn-warning.active:hover,.btn-warning:active.focus,.btn-warning:active:focus,.btn-warning:active:hover,.open>.dropdown-toggle.btn-warning.focus,.open>.dropdown-toggle.btn-warning:focus,.open>.dropdown-toggle.btn-warning:hover{color:#fff;background-color:#d58512;border-color:#985f0d}.btn-warning.active,.btn-warning:active,.open>.dropdown-toggle.btn-warning{background-image:none}.btn-warning.disabled.focus,.btn-warning.disabled:focus,.btn-warning.disabled:hover,.btn-warning[disabled].focus,.btn-warning[disabled]:focus,.btn-warning[disabled]:hover,fieldset[disabled] .btn-warning.focus,fieldset[disabled] .btn-warning:focus,fieldset[disabled] .btn-warning:hover{background-color:#f0ad4e;border-color:#eea236}.btn-warning .badge{color:#f0ad4e;background-color:#fff}.btn-danger{color:#fff;background-color:#d9534f;border-color:#d43f3a}.btn-danger.focus,.btn-danger:focus{color:#fff;background-color:#c9302c;border-color:#761c19}.btn-danger:hover{color:#fff;background-color:#c9302c;border-color:#ac2925}.btn-danger.active,.btn-danger:active,.open>.dropdown-toggle.btn-danger{color:#fff;background-color:#c9302c;border-color:#ac2925}.btn-danger.active.focus,.btn-danger.active:focus,.btn-danger.active:hover,.btn-danger:active.focus,.btn-danger:active:focus,.btn-danger:active:hover,.open>.dropdown-toggle.btn-danger.focus,.open>.dropdown-toggle.btn-danger:focus,.open>.dropdown-toggle.btn-danger:hover{color:#fff;background-color:#ac2925;border-color:#761c19}.btn-danger.active,.btn-danger:active,.open>.dropdown-toggle.btn-danger{background-image:none}.btn-danger.disabled.focus,.btn-danger.disabled:focus,.btn-danger.disabled:hover,.btn-danger[disabled].focus,.btn-danger[disabled]:focus,.btn-danger[disabled]:hover,fieldset[disabled] .btn-danger.focus,fieldset[disabled] .btn-danger:focus,fieldset[disabled] .btn-danger:hover{background-color:#d9534f;border-color:#d43f3a}.btn-danger .badge{color:#d9534f;background-color:#fff}.btn-link{font-weight:400;color:#337ab7;border-radius:0}.btn-link,.btn-link.active,.btn-link:active,.btn-link[disabled],fieldset[disabled] .btn-link{background-color:transparent;-webkit-box-shadow:none;box-shadow:none}.btn-link,.btn-link:active,.btn-link:focus,.btn-link:hover{border-color:transparent}.btn-link:focus,.btn-link:hover{color:#23527c;text-decoration:underline;background-color:transparent}.btn-link[disabled]:focus,.btn-link[disabled]:hover,fieldset[disabled] .btn-link:focus,fieldset[disabled] .btn-link:hover{color:#777;text-decoration:none}.btn-group-lg>.btn,.btn-lg{padding:10px 16px;font-size:18px;line-height:1.3333333;border-radius:6px}.btn-group-sm>.btn,.btn-sm{padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}.btn-group-xs>.btn,.btn-xs{padding:1px 5px;font-size:12px;line-height:1.5;border-radius:3px}.btn-block{display:block;width:100%}.btn-block+.btn-block{margin-top:5px}input[type=button].btn-block,input[type=reset].btn-block,input[type=submit].btn-block{width:100%}.fade{opacity:0;-webkit-transition:opacity .15s linear;-o-transition:opacity .15s linear;transition:opacity .15s linear}.fade.in{opacity:1}.collapse{display:none}.collapse.in{display:block}tr.collapse.in{display:table-row}tbody.collapse.in{display:table-row-group}.collapsing{position:relative;height:0;overflow:hidden;-webkit-transition-timing-function:ease;-o-transition-timing-function:ease;transition-timing-function:ease;-webkit-transition-duration:.35s;-o-transition-duration:.35s;transition-duration:.35s;-webkit-transition-property:height,visibility;-o-transition-property:height,visibility;transition-property:height,visibility}.caret{display:inline-block;width:0;height:0;margin-left:2px;vertical-align:middle;border-top:4px dashed;border-top:4px solid\9;border-right:4px solid transparent;border-left:4px solid transparent}.dropdown,.dropup{position:relative}.dropdown-toggle:focus{outline:0}.dropdown-menu{position:absolute;top:100%;left:0;z-index:1000;display:none;float:left;min-width:160px;padding:5px 0;margin:2px 0 0;font-size:14px;text-align:left;list-style:none;background-color:#fff;-webkit-background-clip:padding-box;background-clip:padding-box;border:1px solid #ccc;border:1px solid rgba(0,0,0,.15);border-radius:4px;-webkit-box-shadow:0 6px 12px rgba(0,0,0,.175);box-shadow:0 6px 12px rgba(0,0,0,.175)}.dropdown-menu.pull-right{right:0;left:auto}.dropdown-menu .divider{height:1px;margin:9px 0;overflow:hidden;background-color:#e5e5e5}.dropdown-menu>li>a{display:block;padding:3px 20px;clear:both;font-weight:400;line-height:1.42857143;color:#333;white-space:nowrap}.dropdown-menu>li>a:focus,.dropdown-menu>li>a:hover{color:#262626;text-decoration:none;background-color:#f5f5f5}.dropdown-menu>.active>a,.dropdown-menu>.active>a:focus,.dropdown-menu>.active>a:hover{color:#fff;text-decoration:none;background-color:#337ab7;outline:0}.dropdown-menu>.disabled>a,.dropdown-menu>.disabled>a:focus,.dropdown-menu>.disabled>a:hover{color:#777}.dropdown-menu>.disabled>a:focus,.dropdown-menu>.disabled>a:hover{text-decoration:none;cursor:not-allowed;background-color:transparent;background-image:none;filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.open>.dropdown-menu{display:block}.open>a{outline:0}.dropdown-menu-right{right:0;left:auto}.dropdown-menu-left{right:auto;left:0}.dropdown-header{display:block;padding:3px 20px;font-size:12px;line-height:1.42857143;color:#777;white-space:nowrap}.dropdown-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;z-index:990}.pull-right>.dropdown-menu{right:0;left:auto}.dropup .caret,.navbar-fixed-bottom .dropdown .caret{content:"";border-top:0;border-bottom:4px dashed;border-bottom:4px solid\9}.dropup .dropdown-menu,.navbar-fixed-bottom .dropdown .dropdown-menu{top:auto;bottom:100%;margin-bottom:2px}@media (min-width:768px){.navbar-right .dropdown-menu{right:0;left:auto}.navbar-right .dropdown-menu-left{right:auto;left:0}}.btn-group,.btn-group-vertical{position:relative;display:inline-block;vertical-align:middle}.btn-group-vertical>.btn,.btn-group>.btn{position:relative;float:left}.btn-group-vertical>.btn.active,.btn-group-vertical>.btn:active,.btn-group-vertical>.btn:focus,.btn-group-vertical>.btn:hover,.btn-group>.btn.active,.btn-group>.btn:active,.btn-group>.btn:focus,.btn-group>.btn:hover{z-index:2}.btn-group .btn+.btn,.btn-group .btn+.btn-group,.btn-group .btn-group+.btn,.btn-group .btn-group+.btn-group{margin-left:-1px}.btn-toolbar{margin-left:-5px}.btn-toolbar .btn,.btn-toolbar .btn-group,.btn-toolbar .input-group{float:left}.btn-toolbar>.btn,.btn-toolbar>.btn-group,.btn-toolbar>.input-group{margin-left:5px}.btn-group>.btn:not(:first-child):not(:last-child):not(.dropdown-toggle){border-radius:0}.btn-group>.btn:first-child{margin-left:0}.btn-group>.btn:first-child:not(:last-child):not(.dropdown-toggle){border-top-right-radius:0;border-bottom-right-radius:0}.btn-group>.btn:last-child:not(:first-child),.btn-group>.dropdown-toggle:not(:first-child){border-top-left-radius:0;border-bottom-left-radius:0}.btn-group>.btn-group{float:left}.btn-group>.btn-group:not(:first-child):not(:last-child)>.btn{border-radius:0}.btn-group>.btn-group:first-child:not(:last-child)>.btn:last-child,.btn-group>.btn-group:first-child:not(:last-child)>.dropdown-toggle{border-top-right-radius:0;border-bottom-right-radius:0}.btn-group>.btn-group:last-child:not(:first-child)>.btn:first-child{border-top-left-radius:0;border-bottom-left-radius:0}.btn-group .dropdown-toggle:active,.btn-group.open .dropdown-toggle{outline:0}.btn-group>.btn+.dropdown-toggle{padding-right:8px;padding-left:8px}.btn-group>.btn-lg+.dropdown-toggle{padding-right:12px;padding-left:12px}.btn-group.open .dropdown-toggle{-webkit-box-shadow:inset 0 3px 5px rgba(0,0,0,.125);box-shadow:inset 0 3px 5px rgba(0,0,0,.125)}.btn-group.open .dropdown-toggle.btn-link{-webkit-box-shadow:none;box-shadow:none}.btn .caret{margin-left:0}.btn-lg .caret{border-width:5px 5px 0;border-bottom-width:0}.dropup .btn-lg .caret{border-width:0 5px 5px}.btn-group-vertical>.btn,.btn-group-vertical>.btn-group,.btn-group-vertical>.btn-group>.btn{display:block;float:none;width:100%;max-width:100%}.btn-group-vertical>.btn-group>.btn{float:none}.btn-group-vertical>.btn+.btn,.btn-group-vertical>.btn+.btn-group,.btn-group-vertical>.btn-group+.btn,.btn-group-vertical>.btn-group+.btn-group{margin-top:-1px;margin-left:0}.btn-group-vertical>.btn:not(:first-child):not(:last-child){border-radius:0}.btn-group-vertical>.btn:first-child:not(:last-child){border-top-left-radius:4px;border-top-right-radius:4px;border-bottom-right-radius:0;border-bottom-left-radius:0}.btn-group-vertical>.btn:last-child:not(:first-child){border-top-left-radius:0;border-top-right-radius:0;border-bottom-right-radius:4px;border-bottom-left-radius:4px}.btn-group-vertical>.btn-group:not(:first-child):not(:last-child)>.btn{border-radius:0}.btn-group-vertical>.btn-group:first-child:not(:last-child)>.btn:last-child,.btn-group-vertical>.btn-group:first-child:not(:last-child)>.dropdown-toggle{border-bottom-right-radius:0;border-bottom-left-radius:0}.btn-group-vertical>.btn-group:last-child:not(:first-child)>.btn:first-child{border-top-left-radius:0;border-top-right-radius:0}.btn-group-justified{display:table;width:100%;table-layout:fixed;border-collapse:separate}.btn-group-justified>.btn,.btn-group-justified>.btn-group{display:table-cell;float:none;width:1%}.btn-group-justified>.btn-group .btn{width:100%}.btn-group-justified>.btn-group .dropdown-menu{left:auto}[data-toggle=buttons]>.btn input[type=checkbox],[data-toggle=buttons]>.btn input[type=radio],[data-toggle=buttons]>.btn-group>.btn input[type=checkbox],[data-toggle=buttons]>.btn-group>.btn input[type=radio]{position:absolute;clip:rect(0,0,0,0);pointer-events:none}.input-group{position:relative;display:table;border-collapse:separate}.input-group[class*=col-]{float:none;padding-right:0;padding-left:0}.input-group .form-control{position:relative;z-index:2;float:left;width:100%;margin-bottom:0}.input-group .form-control:focus{z-index:3}.input-group-lg>.form-control,.input-group-lg>.input-group-addon,.input-group-lg>.input-group-btn>.btn{height:46px;padding:10px 16px;font-size:18px;line-height:1.3333333;border-radius:6px}select.input-group-lg>.form-control,select.input-group-lg>.input-group-addon,select.input-group-lg>.input-group-btn>.btn{height:46px;line-height:46px}select[multiple].input-group-lg>.form-control,select[multiple].input-group-lg>.input-group-addon,select[multiple].input-group-lg>.input-group-btn>.btn,textarea.input-group-lg>.form-control,textarea.input-group-lg>.input-group-addon,textarea.input-group-lg>.input-group-btn>.btn{height:auto}.input-group-sm>.form-control,.input-group-sm>.input-group-addon,.input-group-sm>.input-group-btn>.btn{height:30px;padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}select.input-group-sm>.form-control,select.input-group-sm>.input-group-addon,select.input-group-sm>.input-group-btn>.btn{height:30px;line-height:30px}select[multiple].input-group-sm>.form-control,select[multiple].input-group-sm>.input-group-addon,select[multiple].input-group-sm>.input-group-btn>.btn,textarea.input-group-sm>.form-control,textarea.input-group-sm>.input-group-addon,textarea.input-group-sm>.input-group-btn>.btn{height:auto}.input-group .form-control,.input-group-addon,.input-group-btn{display:table-cell}.input-group .form-control:not(:first-child):not(:last-child),.input-group-addon:not(:first-child):not(:last-child),.input-group-btn:not(:first-child):not(:last-child){border-radius:0}.input-group-addon,.input-group-btn{width:1%;white-space:nowrap;vertical-align:middle}.input-group-addon{padding:6px 12px;font-size:14px;font-weight:400;line-height:1;color:#555;text-align:center;background-color:#eee;border:1px solid #ccc;border-radius:4px}.input-group-addon.input-sm{padding:5px 10px;font-size:12px;border-radius:3px}.input-group-addon.input-lg{padding:10px 16px;font-size:18px;border-radius:6px}.input-group-addon input[type=checkbox],.input-group-addon input[type=radio]{margin-top:0}.input-group .form-control:first-child,.input-group-addon:first-child,.input-group-btn:first-child>.btn,.input-group-btn:first-child>.btn-group>.btn,.input-group-btn:first-child>.dropdown-toggle,.input-group-btn:last-child>.btn-group:not(:last-child)>.btn,.input-group-btn:last-child>.btn:not(:last-child):not(.dropdown-toggle){border-top-right-radius:0;border-bottom-right-radius:0}.input-group-addon:first-child{border-right:0}.input-group .form-control:last-child,.input-group-addon:last-child,.input-group-btn:first-child>.btn-group:not(:first-child)>.btn,.input-group-btn:first-child>.btn:not(:first-child),.input-group-btn:last-child>.btn,.input-group-btn:last-child>.btn-group>.btn,.input-group-btn:last-child>.dropdown-toggle{border-top-left-radius:0;border-bottom-left-radius:0}.input-group-addon:last-child{border-left:0}.input-group-btn{position:relative;font-size:0;white-space:nowrap}.input-group-btn>.btn{position:relative}.input-group-btn>.btn+.btn{margin-left:-1px}.input-group-btn>.btn:active,.input-group-btn>.btn:focus,.input-group-btn>.btn:hover{z-index:2}.input-group-btn:first-child>.btn,.input-group-btn:first-child>.btn-group{margin-right:-1px}.input-group-btn:last-child>.btn,.input-group-btn:last-child>.btn-group{z-index:2;margin-left:-1px}.nav{padding-left:0;margin-bottom:0;list-style:none}.nav>li{position:relative;display:block}.nav>li>a{position:relative;display:block;padding:10px 15px}.nav>li>a:focus,.nav>li>a:hover{text-decoration:none;background-color:#eee}.nav>li.disabled>a{color:#777}.nav>li.disabled>a:focus,.nav>li.disabled>a:hover{color:#777;text-decoration:none;cursor:not-allowed;background-color:transparent}.nav .open>a,.nav .open>a:focus,.nav .open>a:hover{background-color:#eee;border-color:#337ab7}.nav .nav-divider{height:1px;margin:9px 0;overflow:hidden;background-color:#e5e5e5}.nav>li>a>img{max-width:none}.nav-tabs{border-bottom:1px solid #ddd}.nav-tabs>li{float:left;margin-bottom:-1px}.nav-tabs>li>a{margin-right:2px;line-height:1.42857143;border:1px solid transparent;border-radius:4px 4px 0 0}.nav-tabs>li>a:hover{border-color:#eee #eee #ddd}.nav-tabs>li.active>a,.nav-tabs>li.active>a:focus,.nav-tabs>li.active>a:hover{color:#555;cursor:default;background-color:#fff;border:1px solid #ddd;border-bottom-color:transparent}.nav-tabs.nav-justified{width:100%;border-bottom:0}.nav-tabs.nav-justified>li{float:none}.nav-tabs.nav-justified>li>a{margin-bottom:5px;text-align:center}.nav-tabs.nav-justified>.dropdown .dropdown-menu{top:auto;left:auto}@media (min-width:768px){.nav-tabs.nav-justified>li{display:table-cell;width:1%}.nav-tabs.nav-justified>li>a{margin-bottom:0}}.nav-tabs.nav-justified>li>a{margin-right:0;border-radius:4px}.nav-tabs.nav-justified>.active>a,.nav-tabs.nav-justified>.active>a:focus,.nav-tabs.nav-justified>.active>a:hover{border:1px solid #ddd}@media (min-width:768px){.nav-tabs.nav-justified>li>a{border-bottom:1px solid #ddd;border-radius:4px 4px 0 0}.nav-tabs.nav-justified>.active>a,.nav-tabs.nav-justified>.active>a:focus,.nav-tabs.nav-justified>.active>a:hover{border-bottom-color:#fff}}.nav-pills>li{float:left}.nav-pills>li>a{border-radius:4px}.nav-pills>li+li{margin-left:2px}.nav-pills>li.active>a,.nav-pills>li.active>a:focus,.nav-pills>li.active>a:hover{color:#fff;background-color:#337ab7}.nav-stacked>li{float:none}.nav-stacked>li+li{margin-top:2px;margin-left:0}.nav-justified{width:100%}.nav-justified>li{float:none}.nav-justified>li>a{margin-bottom:5px;text-align:center}.nav-justified>.dropdown .dropdown-menu{top:auto;left:auto}@media (min-width:768px){.nav-justified>li{display:table-cell;width:1%}.nav-justified>li>a{margin-bottom:0}}.nav-tabs-justified{border-bottom:0}.nav-tabs-justified>li>a{margin-right:0;border-radius:4px}.nav-tabs-justified>.active>a,.nav-tabs-justified>.active>a:focus,.nav-tabs-justified>.active>a:hover{border:1px solid #ddd}@media (min-width:768px){.nav-tabs-justified>li>a{border-bottom:1px solid #ddd;border-radius:4px 4px 0 0}.nav-tabs-justified>.active>a,.nav-tabs-justified>.active>a:focus,.nav-tabs-justified>.active>a:hover{border-bottom-color:#fff}}.tab-content>.tab-pane{display:none}.tab-content>.active{display:block}.nav-tabs .dropdown-menu{margin-top:-1px;border-top-left-radius:0;border-top-right-radius:0}.navbar{position:relative;min-height:50px;margin-bottom:20px;border:1px solid transparent}@media (min-width:768px){.navbar{border-radius:4px}}@media (min-width:768px){.navbar-header{float:left}}.navbar-collapse{padding-right:15px;padding-left:15px;overflow-x:visible;-webkit-overflow-scrolling:touch;border-top:1px solid transparent;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.1);box-shadow:inset 0 1px 0 rgba(255,255,255,.1)}.navbar-collapse.in{overflow-y:auto}@media (min-width:768px){.navbar-collapse{width:auto;border-top:0;-webkit-box-shadow:none;box-shadow:none}.navbar-collapse.collapse{display:block!important;height:auto!important;padding-bottom:0;overflow:visible!important}.navbar-collapse.in{overflow-y:visible}.navbar-fixed-bottom .navbar-collapse,.navbar-fixed-top .navbar-collapse,.navbar-static-top .navbar-collapse{padding-right:0;padding-left:0}}.navbar-fixed-bottom .navbar-collapse,.navbar-fixed-top .navbar-collapse{max-height:340px}@media (max-device-width:480px) and (orientation:landscape){.navbar-fixed-bottom .navbar-collapse,.navbar-fixed-top .navbar-collapse{max-height:200px}}.container-fluid>.navbar-collapse,.container-fluid>.navbar-header,.container>.navbar-collapse,.container>.navbar-header{margin-right:-15px;margin-left:-15px}@media (min-width:768px){.container-fluid>.navbar-collapse,.container-fluid>.navbar-header,.container>.navbar-collapse,.container>.navbar-header{margin-right:0;margin-left:0}}.navbar-static-top{z-index:1000;border-width:0 0 1px}@media (min-width:768px){.navbar-static-top{border-radius:0}}.navbar-fixed-bottom,.navbar-fixed-top{position:fixed;right:0;left:0;z-index:1030}@media (min-width:768px){.navbar-fixed-bottom,.navbar-fixed-top{border-radius:0}}.navbar-fixed-top{top:0;border-width:0 0 1px}.navbar-fixed-bottom{bottom:0;margin-bottom:0;border-width:1px 0 0}.navbar-brand{float:left;height:50px;padding:15px 15px;font-size:18px;line-height:20px}.navbar-brand:focus,.navbar-brand:hover{text-decoration:none}.navbar-brand>img{display:block}@media (min-width:768px){.navbar>.container .navbar-brand,.navbar>.container-fluid .navbar-brand{margin-left:-15px}}.navbar-toggle{position:relative;float:right;padding:9px 10px;margin-top:8px;margin-right:15px;margin-bottom:8px;background-color:transparent;background-image:none;border:1px solid transparent;border-radius:4px}.navbar-toggle:focus{outline:0}.navbar-toggle .icon-bar{display:block;width:22px;height:2px;border-radius:1px}.navbar-toggle .icon-bar+.icon-bar{margin-top:4px}@media (min-width:768px){.navbar-toggle{display:none}}.navbar-nav{margin:7.5px -15px}.navbar-nav>li>a{padding-top:10px;padding-bottom:10px;line-height:20px}@media (max-width:767px){.navbar-nav .open .dropdown-menu{position:static;float:none;width:auto;margin-top:0;background-color:transparent;border:0;-webkit-box-shadow:none;box-shadow:none}.navbar-nav .open .dropdown-menu .dropdown-header,.navbar-nav .open .dropdown-menu>li>a{padding:5px 15px 5px 25px}.navbar-nav .open .dropdown-menu>li>a{line-height:20px}.navbar-nav .open .dropdown-menu>li>a:focus,.navbar-nav .open .dropdown-menu>li>a:hover{background-image:none}}@media (min-width:768px){.navbar-nav{float:left;margin:0}.navbar-nav>li{float:left}.navbar-nav>li>a{padding-top:15px;padding-bottom:15px}}.navbar-form{padding:10px 15px;margin-top:8px;margin-right:-15px;margin-bottom:8px;margin-left:-15px;border-top:1px solid transparent;border-bottom:1px solid transparent;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.1),0 1px 0 rgba(255,255,255,.1);box-shadow:inset 0 1px 0 rgba(255,255,255,.1),0 1px 0 rgba(255,255,255,.1)}@media (min-width:768px){.navbar-form .form-group{display:inline-block;margin-bottom:0;vertical-align:middle}.navbar-form .form-control{display:inline-block;width:auto;vertical-align:middle}.navbar-form .form-control-static{display:inline-block}.navbar-form .input-group{display:inline-table;vertical-align:middle}.navbar-form .input-group .form-control,.navbar-form .input-group .input-group-addon,.navbar-form .input-group .input-group-btn{width:auto}.navbar-form .input-group>.form-control{width:100%}.navbar-form .control-label{margin-bottom:0;vertical-align:middle}.navbar-form .checkbox,.navbar-form .radio{display:inline-block;margin-top:0;margin-bottom:0;vertical-align:middle}.navbar-form .checkbox label,.navbar-form .radio label{padding-left:0}.navbar-form .checkbox input[type=checkbox],.navbar-form .radio input[type=radio]{position:relative;margin-left:0}.navbar-form .has-feedback .form-control-feedback{top:0}}@media (max-width:767px){.navbar-form .form-group{margin-bottom:5px}.navbar-form .form-group:last-child{margin-bottom:0}}@media (min-width:768px){.navbar-form{width:auto;padding-top:0;padding-bottom:0;margin-right:0;margin-left:0;border:0;-webkit-box-shadow:none;box-shadow:none}}.navbar-nav>li>.dropdown-menu{margin-top:0;border-top-left-radius:0;border-top-right-radius:0}.navbar-fixed-bottom .navbar-nav>li>.dropdown-menu{margin-bottom:0;border-top-left-radius:4px;border-top-right-radius:4px;border-bottom-right-radius:0;border-bottom-left-radius:0}.navbar-btn{margin-top:8px;margin-bottom:8px}.navbar-btn.btn-sm{margin-top:10px;margin-bottom:10px}.navbar-btn.btn-xs{margin-top:14px;margin-bottom:14px}.navbar-text{margin-top:15px;margin-bottom:15px}@media (min-width:768px){.navbar-text{float:left;margin-right:15px;margin-left:15px}}@media (min-width:768px){.navbar-left{float:left!important}.navbar-right{float:right!important;margin-right:-15px}.navbar-right~.navbar-right{margin-right:0}}.navbar-default{background-color:#f8f8f8;border-color:#e7e7e7}.navbar-default .navbar-brand{color:#777}.navbar-default .navbar-brand:focus,.navbar-default .navbar-brand:hover{color:#5e5e5e;background-color:transparent}.navbar-default .navbar-text{color:#777}.navbar-default .navbar-nav>li>a{color:#777}.navbar-default .navbar-nav>li>a:focus,.navbar-default .navbar-nav>li>a:hover{color:#333;background-color:transparent}.navbar-default .navbar-nav>.active>a,.navbar-default .navbar-nav>.active>a:focus,.navbar-default .navbar-nav>.active>a:hover{color:#555;background-color:#e7e7e7}.navbar-default .navbar-nav>.disabled>a,.navbar-default .navbar-nav>.disabled>a:focus,.navbar-default .navbar-nav>.disabled>a:hover{color:#ccc;background-color:transparent}.navbar-default .navbar-toggle{border-color:#ddd}.navbar-default .navbar-toggle:focus,.navbar-default .navbar-toggle:hover{background-color:#ddd}.navbar-default .navbar-toggle .icon-bar{background-color:#888}.navbar-default .navbar-collapse,.navbar-default .navbar-form{border-color:#e7e7e7}.navbar-default .navbar-nav>.open>a,.navbar-default .navbar-nav>.open>a:focus,.navbar-default .navbar-nav>.open>a:hover{color:#555;background-color:#e7e7e7}@media (max-width:767px){.navbar-default .navbar-nav .open .dropdown-menu>li>a{color:#777}.navbar-default .navbar-nav .open .dropdown-menu>li>a:focus,.navbar-default .navbar-nav .open .dropdown-menu>li>a:hover{color:#333;background-color:transparent}.navbar-default .navbar-nav .open .dropdown-menu>.active>a,.navbar-default .navbar-nav .open .dropdown-menu>.active>a:focus,.navbar-default .navbar-nav .open .dropdown-menu>.active>a:hover{color:#555;background-color:#e7e7e7}.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a,.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a:focus,.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a:hover{color:#ccc;background-color:transparent}}.navbar-default .navbar-link{color:#777}.navbar-default .navbar-link:hover{color:#333}.navbar-default .btn-link{color:#777}.navbar-default .btn-link:focus,.navbar-default .btn-link:hover{color:#333}.navbar-default .btn-link[disabled]:focus,.navbar-default .btn-link[disabled]:hover,fieldset[disabled] .navbar-default .btn-link:focus,fieldset[disabled] .navbar-default .btn-link:hover{color:#ccc}.navbar-inverse{background-color:#222;border-color:#080808}.navbar-inverse .navbar-brand{color:#9d9d9d}.navbar-inverse .navbar-brand:focus,.navbar-inverse .navbar-brand:hover{color:#fff;background-color:transparent}.navbar-inverse .navbar-text{color:#9d9d9d}.navbar-inverse .navbar-nav>li>a{color:#9d9d9d}.navbar-inverse .navbar-nav>li>a:focus,.navbar-inverse .navbar-nav>li>a:hover{color:#fff;background-color:transparent}.navbar-inverse .navbar-nav>.active>a,.navbar-inverse .navbar-nav>.active>a:focus,.navbar-inverse .navbar-nav>.active>a:hover{color:#fff;background-color:#080808}.navbar-inverse .navbar-nav>.disabled>a,.navbar-inverse .navbar-nav>.disabled>a:focus,.navbar-inverse .navbar-nav>.disabled>a:hover{color:#444;background-color:transparent}.navbar-inverse .navbar-toggle{border-color:#333}.navbar-inverse .navbar-toggle:focus,.navbar-inverse .navbar-toggle:hover{background-color:#333}.navbar-inverse .navbar-toggle .icon-bar{background-color:#fff}.navbar-inverse .navbar-collapse,.navbar-inverse .navbar-form{border-color:#101010}.navbar-inverse .navbar-nav>.open>a,.navbar-inverse .navbar-nav>.open>a:focus,.navbar-inverse .navbar-nav>.open>a:hover{color:#fff;background-color:#080808}@media (max-width:767px){.navbar-inverse .navbar-nav .open .dropdown-menu>.dropdown-header{border-color:#080808}.navbar-inverse .navbar-nav .open .dropdown-menu .divider{background-color:#080808}.navbar-inverse .navbar-nav .open .dropdown-menu>li>a{color:#9d9d9d}.navbar-inverse .navbar-nav .open .dropdown-menu>li>a:focus,.navbar-inverse .navbar-nav .open .dropdown-menu>li>a:hover{color:#fff;background-color:transparent}.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a,.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a:focus,.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a:hover{color:#fff;background-color:#080808}.navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a,.navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a:focus,.navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a:hover{color:#444;background-color:transparent}}.navbar-inverse .navbar-link{color:#9d9d9d}.navbar-inverse .navbar-link:hover{color:#fff}.navbar-inverse .btn-link{color:#9d9d9d}.navbar-inverse .btn-link:focus,.navbar-inverse .btn-link:hover{color:#fff}.navbar-inverse .btn-link[disabled]:focus,.navbar-inverse .btn-link[disabled]:hover,fieldset[disabled] .navbar-inverse .btn-link:focus,fieldset[disabled] .navbar-inverse .btn-link:hover{color:#444}.breadcrumb{padding:8px 15px;margin-bottom:20px;list-style:none;background-color:#f5f5f5;border-radius:4px}.breadcrumb>li{display:inline-block}.breadcrumb>li+li:before{padding:0 5px;color:#ccc;content:"/\00a0"}.breadcrumb>.active{color:#777}.pagination{display:inline-block;padding-left:0;margin:20px 0;border-radius:4px}.pagination>li{display:inline}.pagination>li>a,.pagination>li>span{position:relative;float:left;padding:6px 12px;margin-left:-1px;line-height:1.42857143;color:#337ab7;text-decoration:none;background-color:#fff;border:1px solid #ddd}.pagination>li:first-child>a,.pagination>li:first-child>span{margin-left:0;border-top-left-radius:4px;border-bottom-left-radius:4px}.pagination>li:last-child>a,.pagination>li:last-child>span{border-top-right-radius:4px;border-bottom-right-radius:4px}.pagination>li>a:focus,.pagination>li>a:hover,.pagination>li>span:focus,.pagination>li>span:hover{z-index:2;color:#23527c;background-color:#eee;border-color:#ddd}.pagination>.active>a,.pagination>.active>a:focus,.pagination>.active>a:hover,.pagination>.active>span,.pagination>.active>span:focus,.pagination>.active>span:hover{z-index:3;color:#fff;cursor:default;background-color:#337ab7;border-color:#337ab7}.pagination>.disabled>a,.pagination>.disabled>a:focus,.pagination>.disabled>a:hover,.pagination>.disabled>span,.pagination>.disabled>span:focus,.pagination>.disabled>span:hover{color:#777;cursor:not-allowed;background-color:#fff;border-color:#ddd}.pagination-lg>li>a,.pagination-lg>li>span{padding:10px 16px;font-size:18px;line-height:1.3333333}.pagination-lg>li:first-child>a,.pagination-lg>li:first-child>span{border-top-left-radius:6px;border-bottom-left-radius:6px}.pagination-lg>li:last-child>a,.pagination-lg>li:last-child>span{border-top-right-radius:6px;border-bottom-right-radius:6px}.pagination-sm>li>a,.pagination-sm>li>span{padding:5px 10px;font-size:12px;line-height:1.5}.pagination-sm>li:first-child>a,.pagination-sm>li:first-child>span{border-top-left-radius:3px;border-bottom-left-radius:3px}.pagination-sm>li:last-child>a,.pagination-sm>li:last-child>span{border-top-right-radius:3px;border-bottom-right-radius:3px}.pager{padding-left:0;margin:20px 0;text-align:center;list-style:none}.pager li{display:inline}.pager li>a,.pager li>span{display:inline-block;padding:5px 14px;background-color:#fff;border:1px solid #ddd;border-radius:15px}.pager li>a:focus,.pager li>a:hover{text-decoration:none;background-color:#eee}.pager .next>a,.pager .next>span{float:right}.pager .previous>a,.pager .previous>span{float:left}.pager .disabled>a,.pager .disabled>a:focus,.pager .disabled>a:hover,.pager .disabled>span{color:#777;cursor:not-allowed;background-color:#fff}.label{display:inline;padding:.2em .6em .3em;font-size:75%;font-weight:700;line-height:1;color:#fff;text-align:center;white-space:nowrap;vertical-align:baseline;border-radius:.25em}a.label:focus,a.label:hover{color:#fff;text-decoration:none;cursor:pointer}.label:empty{display:none}.btn .label{position:relative;top:-1px}.label-default{background-color:#777}.label-default[href]:focus,.label-default[href]:hover{background-color:#5e5e5e}.label-primary{background-color:#337ab7}.label-primary[href]:focus,.label-primary[href]:hover{background-color:#286090}.label-success{background-color:#5cb85c}.label-success[href]:focus,.label-success[href]:hover{background-color:#449d44}.label-info{background-color:#5bc0de}.label-info[href]:focus,.label-info[href]:hover{background-color:#31b0d5}.label-warning{background-color:#f0ad4e}.label-warning[href]:focus,.label-warning[href]:hover{background-color:#ec971f}.label-danger{background-color:#d9534f}.label-danger[href]:focus,.label-danger[href]:hover{background-color:#c9302c}.badge{display:inline-block;min-width:10px;padding:3px 7px;font-size:12px;font-weight:700;line-height:1;color:#fff;text-align:center;white-space:nowrap;vertical-align:middle;background-color:#777;border-radius:10px}.badge:empty{display:none}.btn .badge{position:relative;top:-1px}.btn-group-xs>.btn .badge,.btn-xs .badge{top:0;padding:1px 5px}a.badge:focus,a.badge:hover{color:#fff;text-decoration:none;cursor:pointer}.list-group-item.active>.badge,.nav-pills>.active>a>.badge{color:#337ab7;background-color:#fff}.list-group-item>.badge{float:right}.list-group-item>.badge+.badge{margin-right:5px}.nav-pills>li>a>.badge{margin-left:3px}.jumbotron{padding-top:30px;padding-bottom:30px;margin-bottom:30px;color:inherit;background-color:#eee}.jumbotron .h1,.jumbotron h1{color:inherit}.jumbotron p{margin-bottom:15px;font-size:21px;font-weight:200}.jumbotron>hr{border-top-color:#d5d5d5}.container .jumbotron,.container-fluid .jumbotron{padding-right:15px;padding-left:15px;border-radius:6px}.jumbotron .container{max-width:100%}@media screen and (min-width:768px){.jumbotron{padding-top:48px;padding-bottom:48px}.container .jumbotron,.container-fluid .jumbotron{padding-right:60px;padding-left:60px}.jumbotron .h1,.jumbotron h1{font-size:63px}}.thumbnail{display:block;padding:4px;margin-bottom:20px;line-height:1.42857143;background-color:#fff;border:1px solid #ddd;border-radius:4px;-webkit-transition:border .2s ease-in-out;-o-transition:border .2s ease-in-out;transition:border .2s ease-in-out}.thumbnail a>img,.thumbnail>img{margin-right:auto;margin-left:auto}a.thumbnail.active,a.thumbnail:focus,a.thumbnail:hover{border-color:#337ab7}.thumbnail .caption{padding:9px;color:#333}.alert{padding:15px;margin-bottom:20px;border:1px solid transparent;border-radius:4px}.alert h4{margin-top:0;color:inherit}.alert .alert-link{font-weight:700}.alert>p,.alert>ul{margin-bottom:0}.alert>p+p{margin-top:5px}.alert-dismissable,.alert-dismissible{padding-right:35px}.alert-dismissable .close,.alert-dismissible .close{position:relative;top:-2px;right:-21px;color:inherit}.alert-success{color:#3c763d;background-color:#dff0d8;border-color:#d6e9c6}.alert-success hr{border-top-color:#c9e2b3}.alert-success .alert-link{color:#2b542c}.alert-info{color:#31708f;background-color:#d9edf7;border-color:#bce8f1}.alert-info hr{border-top-color:#a6e1ec}.alert-info .alert-link{color:#245269}.alert-warning{color:#8a6d3b;background-color:#fcf8e3;border-color:#faebcc}.alert-warning hr{border-top-color:#f7e1b5}.alert-warning .alert-link{color:#66512c}.alert-danger{color:#a94442;background-color:#f2dede;border-color:#ebccd1}.alert-danger hr{border-top-color:#e4b9c0}.alert-danger .alert-link{color:#843534}@-webkit-keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}@-o-keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}@keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}.progress{height:20px;margin-bottom:20px;overflow:hidden;background-color:#f5f5f5;border-radius:4px;-webkit-box-shadow:inset 0 1px 2px rgba(0,0,0,.1);box-shadow:inset 0 1px 2px rgba(0,0,0,.1)}.progress-bar{float:left;width:0;height:100%;font-size:12px;line-height:20px;color:#fff;text-align:center;background-color:#337ab7;-webkit-box-shadow:inset 0 -1px 0 rgba(0,0,0,.15);box-shadow:inset 0 -1px 0 rgba(0,0,0,.15);-webkit-transition:width .6s ease;-o-transition:width .6s ease;transition:width .6s ease}.progress-bar-striped,.progress-striped .progress-bar{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);-webkit-background-size:40px 40px;background-size:40px 40px}.progress-bar.active,.progress.active .progress-bar{-webkit-animation:progress-bar-stripes 2s linear infinite;-o-animation:progress-bar-stripes 2s linear infinite;animation:progress-bar-stripes 2s linear infinite}.progress-bar-success{background-color:#5cb85c}.progress-striped .progress-bar-success{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)}.progress-bar-info{background-color:#5bc0de}.progress-striped .progress-bar-info{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)}.progress-bar-warning{background-color:#f0ad4e}.progress-striped .progress-bar-warning{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)}.progress-bar-danger{background-color:#d9534f}.progress-striped .progress-bar-danger{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)}.media{margin-top:15px}.media:first-child{margin-top:0}.media,.media-body{overflow:hidden;zoom:1}.media-body{width:10000px}.media-object{display:block}.media-object.img-thumbnail{max-width:none}.media-right,.media>.pull-right{padding-left:10px}.media-left,.media>.pull-left{padding-right:10px}.media-body,.media-left,.media-right{display:table-cell;vertical-align:top}.media-middle{vertical-align:middle}.media-bottom{vertical-align:bottom}.media-heading{margin-top:0;margin-bottom:5px}.media-list{padding-left:0;list-style:none}.list-group{padding-left:0;margin-bottom:20px}.list-group-item{position:relative;display:block;padding:10px 15px;margin-bottom:-1px;background-color:#fff;border:1px solid #ddd}.list-group-item:first-child{border-top-left-radius:4px;border-top-right-radius:4px}.list-group-item:last-child{margin-bottom:0;border-bottom-right-radius:4px;border-bottom-left-radius:4px}a.list-group-item,button.list-group-item{color:#555}a.list-group-item .list-group-item-heading,button.list-group-item .list-group-item-heading{color:#333}a.list-group-item:focus,a.list-group-item:hover,button.list-group-item:focus,button.list-group-item:hover{color:#555;text-decoration:none;background-color:#f5f5f5}button.list-group-item{width:100%;text-align:left}.list-group-item.disabled,.list-group-item.disabled:focus,.list-group-item.disabled:hover{color:#777;cursor:not-allowed;background-color:#eee}.list-group-item.disabled .list-group-item-heading,.list-group-item.disabled:focus .list-group-item-heading,.list-group-item.disabled:hover .list-group-item-heading{color:inherit}.list-group-item.disabled .list-group-item-text,.list-group-item.disabled:focus .list-group-item-text,.list-group-item.disabled:hover .list-group-item-text{color:#777}.list-group-item.active,.list-group-item.active:focus,.list-group-item.active:hover{z-index:2;color:#fff;background-color:#337ab7;border-color:#337ab7}.list-group-item.active .list-group-item-heading,.list-group-item.active .list-group-item-heading>.small,.list-group-item.active .list-group-item-heading>small,.list-group-item.active:focus .list-group-item-heading,.list-group-item.active:focus .list-group-item-heading>.small,.list-group-item.active:focus .list-group-item-heading>small,.list-group-item.active:hover .list-group-item-heading,.list-group-item.active:hover .list-group-item-heading>.small,.list-group-item.active:hover .list-group-item-heading>small{color:inherit}.list-group-item.active .list-group-item-text,.list-group-item.active:focus .list-group-item-text,.list-group-item.active:hover .list-group-item-text{color:#c7ddef}.list-group-item-success{color:#3c763d;background-color:#dff0d8}a.list-group-item-success,button.list-group-item-success{color:#3c763d}a.list-group-item-success .list-group-item-heading,button.list-group-item-success .list-group-item-heading{color:inherit}a.list-group-item-success:focus,a.list-group-item-success:hover,button.list-group-item-success:focus,button.list-group-item-success:hover{color:#3c763d;background-color:#d0e9c6}a.list-group-item-success.active,a.list-group-item-success.active:focus,a.list-group-item-success.active:hover,button.list-group-item-success.active,button.list-group-item-success.active:focus,button.list-group-item-success.active:hover{color:#fff;background-color:#3c763d;border-color:#3c763d}.list-group-item-info{color:#31708f;background-color:#d9edf7}a.list-group-item-info,button.list-group-item-info{color:#31708f}a.list-group-item-info .list-group-item-heading,button.list-group-item-info .list-group-item-heading{color:inherit}a.list-group-item-info:focus,a.list-group-item-info:hover,button.list-group-item-info:focus,button.list-group-item-info:hover{color:#31708f;background-color:#c4e3f3}a.list-group-item-info.active,a.list-group-item-info.active:focus,a.list-group-item-info.active:hover,button.list-group-item-info.active,button.list-group-item-info.active:focus,button.list-group-item-info.active:hover{color:#fff;background-color:#31708f;border-color:#31708f}.list-group-item-warning{color:#8a6d3b;background-color:#fcf8e3}a.list-group-item-warning,button.list-group-item-warning{color:#8a6d3b}a.list-group-item-warning .list-group-item-heading,button.list-group-item-warning .list-group-item-heading{color:inherit}a.list-group-item-warning:focus,a.list-group-item-warning:hover,button.list-group-item-warning:focus,button.list-group-item-warning:hover{color:#8a6d3b;background-color:#faf2cc}a.list-group-item-warning.active,a.list-group-item-warning.active:focus,a.list-group-item-warning.active:hover,button.list-group-item-warning.active,button.list-group-item-warning.active:focus,button.list-group-item-warning.active:hover{color:#fff;background-color:#8a6d3b;border-color:#8a6d3b}.list-group-item-danger{color:#a94442;background-color:#f2dede}a.list-group-item-danger,button.list-group-item-danger{color:#a94442}a.list-group-item-danger .list-group-item-heading,button.list-group-item-danger .list-group-item-heading{color:inherit}a.list-group-item-danger:focus,a.list-group-item-danger:hover,button.list-group-item-danger:focus,button.list-group-item-danger:hover{color:#a94442;background-color:#ebcccc}a.list-group-item-danger.active,a.list-group-item-danger.active:focus,a.list-group-item-danger.active:hover,button.list-group-item-danger.active,button.list-group-item-danger.active:focus,button.list-group-item-danger.active:hover{color:#fff;background-color:#a94442;border-color:#a94442}.list-group-item-heading{margin-top:0;margin-bottom:5px}.list-group-item-text{margin-bottom:0;line-height:1.3}.panel{margin-bottom:20px;background-color:#fff;border:1px solid transparent;border-radius:4px;-webkit-box-shadow:0 1px 1px rgba(0,0,0,.05);box-shadow:0 1px 1px rgba(0,0,0,.05)}.panel-body{padding:15px}.panel-heading{padding:10px 15px;border-bottom:1px solid transparent;border-top-left-radius:3px;border-top-right-radius:3px}.panel-heading>.dropdown .dropdown-toggle{color:inherit}.panel-title{margin-top:0;margin-bottom:0;font-size:16px;color:inherit}.panel-title>.small,.panel-title>.small>a,.panel-title>a,.panel-title>small,.panel-title>small>a{color:inherit}.panel-footer{padding:10px 15px;background-color:#f5f5f5;border-top:1px solid #ddd;border-bottom-right-radius:3px;border-bottom-left-radius:3px}.panel>.list-group,.panel>.panel-collapse>.list-group{margin-bottom:0}.panel>.list-group .list-group-item,.panel>.panel-collapse>.list-group .list-group-item{border-width:1px 0;border-radius:0}.panel>.list-group:first-child .list-group-item:first-child,.panel>.panel-collapse>.list-group:first-child .list-group-item:first-child{border-top:0;border-top-left-radius:3px;border-top-right-radius:3px}.panel>.list-group:last-child .list-group-item:last-child,.panel>.panel-collapse>.list-group:last-child .list-group-item:last-child{border-bottom:0;border-bottom-right-radius:3px;border-bottom-left-radius:3px}.panel>.panel-heading+.panel-collapse>.list-group .list-group-item:first-child{border-top-left-radius:0;border-top-right-radius:0}.panel-heading+.list-group .list-group-item:first-child{border-top-width:0}.list-group+.panel-footer{border-top-width:0}.panel>.panel-collapse>.table,.panel>.table,.panel>.table-responsive>.table{margin-bottom:0}.panel>.panel-collapse>.table caption,.panel>.table caption,.panel>.table-responsive>.table caption{padding-right:15px;padding-left:15px}.panel>.table-responsive:first-child>.table:first-child,.panel>.table:first-child{border-top-left-radius:3px;border-top-right-radius:3px}.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child,.panel>.table:first-child>tbody:first-child>tr:first-child,.panel>.table:first-child>thead:first-child>tr:first-child{border-top-left-radius:3px;border-top-right-radius:3px}.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child td:first-child,.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child th:first-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child td:first-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child th:first-child,.panel>.table:first-child>tbody:first-child>tr:first-child td:first-child,.panel>.table:first-child>tbody:first-child>tr:first-child th:first-child,.panel>.table:first-child>thead:first-child>tr:first-child td:first-child,.panel>.table:first-child>thead:first-child>tr:first-child th:first-child{border-top-left-radius:3px}.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child td:last-child,.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child th:last-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child td:last-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child th:last-child,.panel>.table:first-child>tbody:first-child>tr:first-child td:last-child,.panel>.table:first-child>tbody:first-child>tr:first-child th:last-child,.panel>.table:first-child>thead:first-child>tr:first-child td:last-child,.panel>.table:first-child>thead:first-child>tr:first-child th:last-child{border-top-right-radius:3px}.panel>.table-responsive:last-child>.table:last-child,.panel>.table:last-child{border-bottom-right-radius:3px;border-bottom-left-radius:3px}.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child,.panel>.table:last-child>tbody:last-child>tr:last-child,.panel>.table:last-child>tfoot:last-child>tr:last-child{border-bottom-right-radius:3px;border-bottom-left-radius:3px}.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child td:first-child,.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child th:first-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child td:first-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child th:first-child,.panel>.table:last-child>tbody:last-child>tr:last-child td:first-child,.panel>.table:last-child>tbody:last-child>tr:last-child th:first-child,.panel>.table:last-child>tfoot:last-child>tr:last-child td:first-child,.panel>.table:last-child>tfoot:last-child>tr:last-child th:first-child{border-bottom-left-radius:3px}.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child td:last-child,.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child th:last-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child td:last-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child th:last-child,.panel>.table:last-child>tbody:last-child>tr:last-child td:last-child,.panel>.table:last-child>tbody:last-child>tr:last-child th:last-child,.panel>.table:last-child>tfoot:last-child>tr:last-child td:last-child,.panel>.table:last-child>tfoot:last-child>tr:last-child th:last-child{border-bottom-right-radius:3px}.panel>.panel-body+.table,.panel>.panel-body+.table-responsive,.panel>.table+.panel-body,.panel>.table-responsive+.panel-body{border-top:1px solid #ddd}.panel>.table>tbody:first-child>tr:first-child td,.panel>.table>tbody:first-child>tr:first-child th{border-top:0}.panel>.table-bordered,.panel>.table-responsive>.table-bordered{border:0}.panel>.table-bordered>tbody>tr>td:first-child,.panel>.table-bordered>tbody>tr>th:first-child,.panel>.table-bordered>tfoot>tr>td:first-child,.panel>.table-bordered>tfoot>tr>th:first-child,.panel>.table-bordered>thead>tr>td:first-child,.panel>.table-bordered>thead>tr>th:first-child,.panel>.table-responsive>.table-bordered>tbody>tr>td:first-child,.panel>.table-responsive>.table-bordered>tbody>tr>th:first-child,.panel>.table-responsive>.table-bordered>tfoot>tr>td:first-child,.panel>.table-responsive>.table-bordered>tfoot>tr>th:first-child,.panel>.table-responsive>.table-bordered>thead>tr>td:first-child,.panel>.table-responsive>.table-bordered>thead>tr>th:first-child{border-left:0}.panel>.table-bordered>tbody>tr>td:last-child,.panel>.table-bordered>tbody>tr>th:last-child,.panel>.table-bordered>tfoot>tr>td:last-child,.panel>.table-bordered>tfoot>tr>th:last-child,.panel>.table-bordered>thead>tr>td:last-child,.panel>.table-bordered>thead>tr>th:last-child,.panel>.table-responsive>.table-bordered>tbody>tr>td:last-child,.panel>.table-responsive>.table-bordered>tbody>tr>th:last-child,.panel>.table-responsive>.table-bordered>tfoot>tr>td:last-child,.panel>.table-responsive>.table-bordered>tfoot>tr>th:last-child,.panel>.table-responsive>.table-bordered>thead>tr>td:last-child,.panel>.table-responsive>.table-bordered>thead>tr>th:last-child{border-right:0}.panel>.table-bordered>tbody>tr:first-child>td,.panel>.table-bordered>tbody>tr:first-child>th,.panel>.table-bordered>thead>tr:first-child>td,.panel>.table-bordered>thead>tr:first-child>th,.panel>.table-responsive>.table-bordered>tbody>tr:first-child>td,.panel>.table-responsive>.table-bordered>tbody>tr:first-child>th,.panel>.table-responsive>.table-bordered>thead>tr:first-child>td,.panel>.table-responsive>.table-bordered>thead>tr:first-child>th{border-bottom:0}.panel>.table-bordered>tbody>tr:last-child>td,.panel>.table-bordered>tbody>tr:last-child>th,.panel>.table-bordered>tfoot>tr:last-child>td,.panel>.table-bordered>tfoot>tr:last-child>th,.panel>.table-responsive>.table-bordered>tbody>tr:last-child>td,.panel>.table-responsive>.table-bordered>tbody>tr:last-child>th,.panel>.table-responsive>.table-bordered>tfoot>tr:last-child>td,.panel>.table-responsive>.table-bordered>tfoot>tr:last-child>th{border-bottom:0}.panel>.table-responsive{margin-bottom:0;border:0}.panel-group{margin-bottom:20px}.panel-group .panel{margin-bottom:0;border-radius:4px}.panel-group .panel+.panel{margin-top:5px}.panel-group .panel-heading{border-bottom:0}.panel-group .panel-heading+.panel-collapse>.list-group,.panel-group .panel-heading+.panel-collapse>.panel-body{border-top:1px solid #ddd}.panel-group .panel-footer{border-top:0}.panel-group .panel-footer+.panel-collapse .panel-body{border-bottom:1px solid #ddd}.panel-default{border-color:#ddd}.panel-default>.panel-heading{color:#333;background-color:#f5f5f5;border-color:#ddd}.panel-default>.panel-heading+.panel-collapse>.panel-body{border-top-color:#ddd}.panel-default>.panel-heading .badge{color:#f5f5f5;background-color:#333}.panel-default>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#ddd}.panel-primary{border-color:#337ab7}.panel-primary>.panel-heading{color:#fff;background-color:#337ab7;border-color:#337ab7}.panel-primary>.panel-heading+.panel-collapse>.panel-body{border-top-color:#337ab7}.panel-primary>.panel-heading .badge{color:#337ab7;background-color:#fff}.panel-primary>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#337ab7}.panel-success{border-color:#d6e9c6}.panel-success>.panel-heading{color:#3c763d;background-color:#dff0d8;border-color:#d6e9c6}.panel-success>.panel-heading+.panel-collapse>.panel-body{border-top-color:#d6e9c6}.panel-success>.panel-heading .badge{color:#dff0d8;background-color:#3c763d}.panel-success>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#d6e9c6}.panel-info{border-color:#bce8f1}.panel-info>.panel-heading{color:#31708f;background-color:#d9edf7;border-color:#bce8f1}.panel-info>.panel-heading+.panel-collapse>.panel-body{border-top-color:#bce8f1}.panel-info>.panel-heading .badge{color:#d9edf7;background-color:#31708f}.panel-info>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#bce8f1}.panel-warning{border-color:#faebcc}.panel-warning>.panel-heading{color:#8a6d3b;background-color:#fcf8e3;border-color:#faebcc}.panel-warning>.panel-heading+.panel-collapse>.panel-body{border-top-color:#faebcc}.panel-warning>.panel-heading .badge{color:#fcf8e3;background-color:#8a6d3b}.panel-warning>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#faebcc}.panel-danger{border-color:#ebccd1}.panel-danger>.panel-heading{color:#a94442;background-color:#f2dede;border-color:#ebccd1}.panel-danger>.panel-heading+.panel-collapse>.panel-body{border-top-color:#ebccd1}.panel-danger>.panel-heading .badge{color:#f2dede;background-color:#a94442}.panel-danger>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#ebccd1}.embed-responsive{position:relative;display:block;height:0;padding:0;overflow:hidden}.embed-responsive .embed-responsive-item,.embed-responsive embed,.embed-responsive iframe,.embed-responsive object,.embed-responsive video{position:absolute;top:0;bottom:0;left:0;width:100%;height:100%;border:0}.embed-responsive-16by9{padding-bottom:56.25%}.embed-responsive-4by3{padding-bottom:75%}.well{min-height:20px;padding:19px;margin-bottom:20px;background-color:#f5f5f5;border:1px solid #e3e3e3;border-radius:4px;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.05);box-shadow:inset 0 1px 1px rgba(0,0,0,.05)}.well blockquote{border-color:#ddd;border-color:rgba(0,0,0,.15)}.well-lg{padding:24px;border-radius:6px}.well-sm{padding:9px;border-radius:3px}.close{float:right;font-size:21px;font-weight:700;line-height:1;color:#000;text-shadow:0 1px 0 #fff;filter:alpha(opacity=20);opacity:.2}.close:focus,.close:hover{color:#000;text-decoration:none;cursor:pointer;filter:alpha(opacity=50);opacity:.5}button.close{-webkit-appearance:none;padding:0;cursor:pointer;background:0 0;border:0}.modal-open{overflow:hidden}.modal{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1050;display:none;overflow:hidden;-webkit-overflow-scrolling:touch;outline:0}.modal.fade .modal-dialog{-webkit-transition:-webkit-transform .3s ease-out;-o-transition:-o-transform .3s ease-out;transition:transform .3s ease-out;-webkit-transform:translate(0,-25%);-ms-transform:translate(0,-25%);-o-transform:translate(0,-25%);transform:translate(0,-25%)}.modal.in .modal-dialog{-webkit-transform:translate(0,0);-ms-transform:translate(0,0);-o-transform:translate(0,0);transform:translate(0,0)}.modal-open .modal{overflow-x:hidden;overflow-y:auto}.modal-dialog{position:relative;width:auto;margin:10px}.modal-content{position:relative;background-color:#fff;-webkit-background-clip:padding-box;background-clip:padding-box;border:1px solid #999;border:1px solid rgba(0,0,0,.2);border-radius:6px;outline:0;-webkit-box-shadow:0 3px 9px rgba(0,0,0,.5);box-shadow:0 3px 9px rgba(0,0,0,.5)}.modal-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1040;background-color:#000}.modal-backdrop.fade{filter:alpha(opacity=0);opacity:0}.modal-backdrop.in{filter:alpha(opacity=50);opacity:.5}.modal-header{padding:15px;border-bottom:1px solid #e5e5e5}.modal-header .close{margin-top:-2px}.modal-title{margin:0;line-height:1.42857143}.modal-body{position:relative;padding:15px}.modal-footer{padding:15px;text-align:right;border-top:1px solid #e5e5e5}.modal-footer .btn+.btn{margin-bottom:0;margin-left:5px}.modal-footer .btn-group .btn+.btn{margin-left:-1px}.modal-footer .btn-block+.btn-block{margin-left:0}.modal-scrollbar-measure{position:absolute;top:-9999px;width:50px;height:50px;overflow:scroll}@media (min-width:768px){.modal-dialog{width:600px;margin:30px auto}.modal-content{-webkit-box-shadow:0 5px 15px rgba(0,0,0,.5);box-shadow:0 5px 15px rgba(0,0,0,.5)}.modal-sm{width:300px}}@media (min-width:992px){.modal-lg{width:900px}}.tooltip{position:absolute;z-index:1070;display:block;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:12px;font-style:normal;font-weight:400;line-height:1.42857143;text-align:left;text-align:start;text-decoration:none;text-shadow:none;text-transform:none;letter-spacing:normal;word-break:normal;word-spacing:normal;word-wrap:normal;white-space:normal;filter:alpha(opacity=0);opacity:0;line-break:auto}.tooltip.in{filter:alpha(opacity=90);opacity:.9}.tooltip.top{padding:5px 0;margin-top:-3px}.tooltip.right{padding:0 5px;margin-left:3px}.tooltip.bottom{padding:5px 0;margin-top:3px}.tooltip.left{padding:0 5px;margin-left:-3px}.tooltip-inner{max-width:200px;padding:3px 8px;color:#fff;text-align:center;background-color:#000;border-radius:4px}.tooltip-arrow{position:absolute;width:0;height:0;border-color:transparent;border-style:solid}.tooltip.top .tooltip-arrow{bottom:0;left:50%;margin-left:-5px;border-width:5px 5px 0;border-top-color:#000}.tooltip.top-left .tooltip-arrow{right:5px;bottom:0;margin-bottom:-5px;border-width:5px 5px 0;border-top-color:#000}.tooltip.top-right .tooltip-arrow{bottom:0;left:5px;margin-bottom:-5px;border-width:5px 5px 0;border-top-color:#000}.tooltip.right .tooltip-arrow{top:50%;left:0;margin-top:-5px;border-width:5px 5px 5px 0;border-right-color:#000}.tooltip.left .tooltip-arrow{top:50%;right:0;margin-top:-5px;border-width:5px 0 5px 5px;border-left-color:#000}.tooltip.bottom .tooltip-arrow{top:0;left:50%;margin-left:-5px;border-width:0 5px 5px;border-bottom-color:#000}.tooltip.bottom-left .tooltip-arrow{top:0;right:5px;margin-top:-5px;border-width:0 5px 5px;border-bottom-color:#000}.tooltip.bottom-right .tooltip-arrow{top:0;left:5px;margin-top:-5px;border-width:0 5px 5px;border-bottom-color:#000}.popover{position:absolute;top:0;left:0;z-index:1060;display:none;max-width:276px;padding:1px;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:14px;font-style:normal;font-weight:400;line-height:1.42857143;text-align:left;text-align:start;text-decoration:none;text-shadow:none;text-transform:none;letter-spacing:normal;word-break:normal;word-spacing:normal;word-wrap:normal;white-space:normal;background-color:#fff;-webkit-background-clip:padding-box;background-clip:padding-box;border:1px solid #ccc;border:1px solid rgba(0,0,0,.2);border-radius:6px;-webkit-box-shadow:0 5px 10px rgba(0,0,0,.2);box-shadow:0 5px 10px rgba(0,0,0,.2);line-break:auto}.popover.top{margin-top:-10px}.popover.right{margin-left:10px}.popover.bottom{margin-top:10px}.popover.left{margin-left:-10px}.popover-title{padding:8px 14px;margin:0;font-size:14px;background-color:#f7f7f7;border-bottom:1px solid #ebebeb;border-radius:5px 5px 0 0}.popover-content{padding:9px 14px}.popover>.arrow,.popover>.arrow:after{position:absolute;display:block;width:0;height:0;border-color:transparent;border-style:solid}.popover>.arrow{border-width:11px}.popover>.arrow:after{content:"";border-width:10px}.popover.top>.arrow{bottom:-11px;left:50%;margin-left:-11px;border-top-color:#999;border-top-color:rgba(0,0,0,.25);border-bottom-width:0}.popover.top>.arrow:after{bottom:1px;margin-left:-10px;content:" ";border-top-color:#fff;border-bottom-width:0}.popover.right>.arrow{top:50%;left:-11px;margin-top:-11px;border-right-color:#999;border-right-color:rgba(0,0,0,.25);border-left-width:0}.popover.right>.arrow:after{bottom:-10px;left:1px;content:" ";border-right-color:#fff;border-left-width:0}.popover.bottom>.arrow{top:-11px;left:50%;margin-left:-11px;border-top-width:0;border-bottom-color:#999;border-bottom-color:rgba(0,0,0,.25)}.popover.bottom>.arrow:after{top:1px;margin-left:-10px;content:" ";border-top-width:0;border-bottom-color:#fff}.popover.left>.arrow{top:50%;right:-11px;margin-top:-11px;border-right-width:0;border-left-color:#999;border-left-color:rgba(0,0,0,.25)}.popover.left>.arrow:after{right:1px;bottom:-10px;content:" ";border-right-width:0;border-left-color:#fff}.carousel{position:relative}.carousel-inner{position:relative;width:100%;overflow:hidden}.carousel-inner>.item{position:relative;display:none;-webkit-transition:.6s ease-in-out left;-o-transition:.6s ease-in-out left;transition:.6s ease-in-out left}.carousel-inner>.item>a>img,.carousel-inner>.item>img{line-height:1}@media all and (transform-3d),(-webkit-transform-3d){.carousel-inner>.item{-webkit-transition:-webkit-transform .6s ease-in-out;-o-transition:-o-transform .6s ease-in-out;transition:transform .6s ease-in-out;-webkit-backface-visibility:hidden;backface-visibility:hidden;-webkit-perspective:1000px;perspective:1000px}.carousel-inner>.item.active.right,.carousel-inner>.item.next{left:0;-webkit-transform:translate3d(100%,0,0);transform:translate3d(100%,0,0)}.carousel-inner>.item.active.left,.carousel-inner>.item.prev{left:0;-webkit-transform:translate3d(-100%,0,0);transform:translate3d(-100%,0,0)}.carousel-inner>.item.active,.carousel-inner>.item.next.left,.carousel-inner>.item.prev.right{left:0;-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0)}}.carousel-inner>.active,.carousel-inner>.next,.carousel-inner>.prev{display:block}.carousel-inner>.active{left:0}.carousel-inner>.next,.carousel-inner>.prev{position:absolute;top:0;width:100%}.carousel-inner>.next{left:100%}.carousel-inner>.prev{left:-100%}.carousel-inner>.next.left,.carousel-inner>.prev.right{left:0}.carousel-inner>.active.left{left:-100%}.carousel-inner>.active.right{left:100%}.carousel-control{position:absolute;top:0;bottom:0;left:0;width:15%;font-size:20px;color:#fff;text-align:center;text-shadow:0 1px 2px rgba(0,0,0,.6);background-color:rgba(0,0,0,0);filter:alpha(opacity=50);opacity:.5}.carousel-control.left{background-image:-webkit-linear-gradient(left,rgba(0,0,0,.5) 0,rgba(0,0,0,.0001) 100%);background-image:-o-linear-gradient(left,rgba(0,0,0,.5) 0,rgba(0,0,0,.0001) 100%);background-image:-webkit-gradient(linear,left top,right top,from(rgba(0,0,0,.5)),to(rgba(0,0,0,.0001)));background-image:linear-gradient(to right,rgba(0,0,0,.5) 0,rgba(0,0,0,.0001) 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#80000000', endColorstr='#00000000', GradientType=1);background-repeat:repeat-x}.carousel-control.right{right:0;left:auto;background-image:-webkit-linear-gradient(left,rgba(0,0,0,.0001) 0,rgba(0,0,0,.5) 100%);background-image:-o-linear-gradient(left,rgba(0,0,0,.0001) 0,rgba(0,0,0,.5) 100%);background-image:-webkit-gradient(linear,left top,right top,from(rgba(0,0,0,.0001)),to(rgba(0,0,0,.5)));background-image:linear-gradient(to right,rgba(0,0,0,.0001) 0,rgba(0,0,0,.5) 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#00000000', endColorstr='#80000000', GradientType=1);background-repeat:repeat-x}.carousel-control:focus,.carousel-control:hover{color:#fff;text-decoration:none;filter:alpha(opacity=90);outline:0;opacity:.9}.carousel-control .glyphicon-chevron-left,.carousel-control .glyphicon-chevron-right,.carousel-control .icon-next,.carousel-control .icon-prev{position:absolute;top:50%;z-index:5;display:inline-block;margin-top:-10px}.carousel-control .glyphicon-chevron-left,.carousel-control .icon-prev{left:50%;margin-left:-10px}.carousel-control .glyphicon-chevron-right,.carousel-control .icon-next{right:50%;margin-right:-10px}.carousel-control .icon-next,.carousel-control .icon-prev{width:20px;height:20px;font-family:serif;line-height:1}.carousel-control .icon-prev:before{content:'\2039'}.carousel-control .icon-next:before{content:'\203a'}.carousel-indicators{position:absolute;bottom:10px;left:50%;z-index:15;width:60%;padding-left:0;margin-left:-30%;text-align:center;list-style:none}.carousel-indicators li{display:inline-block;width:10px;height:10px;margin:1px;text-indent:-999px;cursor:pointer;background-color:#000\9;background-color:rgba(0,0,0,0);border:1px solid #fff;border-radius:10px}.carousel-indicators .active{width:12px;height:12px;margin:0;background-color:#fff}.carousel-caption{position:absolute;right:15%;bottom:20px;left:15%;z-index:10;padding-top:20px;padding-bottom:20px;color:#fff;text-align:center;text-shadow:0 1px 2px rgba(0,0,0,.6)}.carousel-caption .btn{text-shadow:none}@media screen and (min-width:768px){.carousel-control .glyphicon-chevron-left,.carousel-control .glyphicon-chevron-right,.carousel-control .icon-next,.carousel-control .icon-prev{width:30px;height:30px;margin-top:-10px;font-size:30px}.carousel-control .glyphicon-chevron-left,.carousel-control .icon-prev{margin-left:-10px}.carousel-control .glyphicon-chevron-right,.carousel-control .icon-next{margin-right:-10px}.carousel-caption{right:20%;left:20%;padding-bottom:30px}.carousel-indicators{bottom:20px}}.btn-group-vertical>.btn-group:after,.btn-group-vertical>.btn-group:before,.btn-toolbar:after,.btn-toolbar:before,.clearfix:after,.clearfix:before,.container-fluid:after,.container-fluid:before,.container:after,.container:before,.dl-horizontal dd:after,.dl-horizontal dd:before,.form-horizontal .form-group:after,.form-horizontal .form-group:before,.modal-footer:after,.modal-footer:before,.modal-header:after,.modal-header:before,.nav:after,.nav:before,.navbar-collapse:after,.navbar-collapse:before,.navbar-header:after,.navbar-header:before,.navbar:after,.navbar:before,.pager:after,.pager:before,.panel-body:after,.panel-body:before,.row:after,.row:before{display:table;content:" "}.btn-group-vertical>.btn-group:after,.btn-toolbar:after,.clearfix:after,.container-fluid:after,.container:after,.dl-horizontal dd:after,.form-horizontal .form-group:after,.modal-footer:after,.modal-header:after,.nav:after,.navbar-collapse:after,.navbar-header:after,.navbar:after,.pager:after,.panel-body:after,.row:after{clear:both}.center-block{display:block;margin-right:auto;margin-left:auto}.pull-right{float:right!important}.pull-left{float:left!important}.hide{display:none!important}.show{display:block!important}.invisible{visibility:hidden}.text-hide{font:0/0 a;color:transparent;text-shadow:none;background-color:transparent;border:0}.hidden{display:none!important}.affix{position:fixed}@-ms-viewport{width:device-width}.visible-lg,.visible-md,.visible-sm,.visible-xs{display:none!important}.visible-lg-block,.visible-lg-inline,.visible-lg-inline-block,.visible-md-block,.visible-md-inline,.visible-md-inline-block,.visible-sm-block,.visible-sm-inline,.visible-sm-inline-block,.visible-xs-block,.visible-xs-inline,.visible-xs-inline-block{display:none!important}@media (max-width:767px){.visible-xs{display:block!important}table.visible-xs{display:table!important}tr.visible-xs{display:table-row!important}td.visible-xs,th.visible-xs{display:table-cell!important}}@media (max-width:767px){.visible-xs-block{display:block!important}}@media (max-width:767px){.visible-xs-inline{display:inline!important}}@media (max-width:767px){.visible-xs-inline-block{display:inline-block!important}}@media (min-width:768px) and (max-width:991px){.visible-sm{display:block!important}table.visible-sm{display:table!important}tr.visible-sm{display:table-row!important}td.visible-sm,th.visible-sm{display:table-cell!important}}@media (min-width:768px) and (max-width:991px){.visible-sm-block{display:block!important}}@media (min-width:768px) and (max-width:991px){.visible-sm-inline{display:inline!important}}@media (min-width:768px) and (max-width:991px){.visible-sm-inline-block{display:inline-block!important}}@media (min-width:992px) and (max-width:1199px){.visible-md{display:block!important}table.visible-md{display:table!important}tr.visible-md{display:table-row!important}td.visible-md,th.visible-md{display:table-cell!important}}@media (min-width:992px) and (max-width:1199px){.visible-md-block{display:block!important}}@media (min-width:992px) and (max-width:1199px){.visible-md-inline{display:inline!important}}@media (min-width:992px) and (max-width:1199px){.visible-md-inline-block{display:inline-block!important}}@media (min-width:1200px){.visible-lg{display:block!important}table.visible-lg{display:table!important}tr.visible-lg{display:table-row!important}td.visible-lg,th.visible-lg{display:table-cell!important}}@media (min-width:1200px){.visible-lg-block{display:block!important}}@media (min-width:1200px){.visible-lg-inline{display:inline!important}}@media (min-width:1200px){.visible-lg-inline-block{display:inline-block!important}}@media (max-width:767px){.hidden-xs{display:none!important}}@media (min-width:768px) and (max-width:991px){.hidden-sm{display:none!important}}@media (min-width:992px) and (max-width:1199px){.hidden-md{display:none!important}}@media (min-width:1200px){.hidden-lg{display:none!important}}.visible-print{display:none!important}@media print{.visible-print{display:block!important}table.visible-print{display:table!important}tr.visible-print{display:table-row!important}td.visible-print,th.visible-print{display:table-cell!important}}.visible-print-block{display:none!important}@media print{.visible-print-block{display:block!important}}.visible-print-inline{display:none!important}@media print{.visible-print-inline{display:inline!important}}.visible-print-inline-block{display:none!important}@media print{.visible-print-inline-block{display:inline-block!important}}@media print{.hidden-print{display:none!important}} +/*# sourceMappingURL=bootstrap.min.css.map */ \ No newline at end of file diff --git a/resource/web/css/c3.css b/hal-core/resources/web/css/lib/c3.css old mode 100755 new mode 100644 similarity index 100% rename from resource/web/css/c3.css rename to hal-core/resources/web/css/lib/c3.css diff --git a/resource/web/css/c3.min.css b/hal-core/resources/web/css/lib/c3.min.css old mode 100755 new mode 100644 similarity index 100% rename from resource/web/css/c3.min.css rename to hal-core/resources/web/css/lib/c3.min.css diff --git a/resource/web/css/jquery.filer.css b/hal-core/resources/web/css/lib/jquery.filer.css old mode 100755 new mode 100644 similarity index 100% rename from resource/web/css/jquery.filer.css rename to hal-core/resources/web/css/lib/jquery.filer.css diff --git a/hal-core/resources/web/css/lib/svg.select.css b/hal-core/resources/web/css/lib/svg.select.css new file mode 100644 index 00000000..18888ab3 --- /dev/null +++ b/hal-core/resources/web/css/lib/svg.select.css @@ -0,0 +1,44 @@ +.svg_select_points_lt{ + cursor: nw-resize; +} +.svg_select_points_rt{ + cursor: ne-resize; +} +.svg_select_points_rb{ + cursor: se-resize; +} +.svg_select_points_lb{ + cursor: sw-resize; +} +.svg_select_points_t{ + cursor: n-resize; +} +.svg_select_points_r{ + cursor: e-resize; +} +.svg_select_points_b{ + cursor: s-resize; +} +.svg_select_points_l{ + cursor: w-resize; +} + +.svg_select_points_rot{ + stroke-width:1; + stroke:black; + fill: #F9FFED; +} + +.svg_select_points_point{ + cursor: move; +} + +.svg_select_boundingRect{ + stroke-width:1; + fill:gray; + stroke-dasharray:10 10; + stroke:black; + stroke-opacity:0.8; + fill-opacity:0.1; + pointer-events:none; /* This ons is needed if you want to deselect or drag the shape*/ +} \ No newline at end of file diff --git a/hal-core/resources/web/css/lib/svg.select.min.css b/hal-core/resources/web/css/lib/svg.select.min.css new file mode 100644 index 00000000..d8345130 --- /dev/null +++ b/hal-core/resources/web/css/lib/svg.select.min.css @@ -0,0 +1 @@ +.svg_select_points_lt{cursor:nw-resize}.svg_select_points_rt{cursor:ne-resize}.svg_select_points_rb{cursor:se-resize}.svg_select_points_lb{cursor:sw-resize}.svg_select_points_t{cursor:n-resize}.svg_select_points_r{cursor:e-resize}.svg_select_points_b{cursor:s-resize}.svg_select_points_l{cursor:w-resize}.svg_select_points_rot{stroke-width:1;stroke:#000;fill:#f9ffed}.svg_select_points_point{cursor:move}.svg_select_boundingRect{stroke-width:1;fill:gray;stroke-dasharray:10 10;stroke:#000;stroke-opacity:.8;fill-opacity:.1;pointer-events:none} \ No newline at end of file diff --git a/resource/web/event_config.tmpl b/hal-core/resources/web/event_config.tmpl old mode 100755 new mode 100644 similarity index 70% rename from resource/web/event_config.tmpl rename to hal-core/resources/web/event_config.tmpl index 5582c92c..e01b5a1a --- a/resource/web/event_config.tmpl +++ b/hal-core/resources/web/event_config.tmpl @@ -8,30 +8,34 @@ + {{#localEvents}} + + {{#detectedEvents}} @@ -70,6 +89,7 @@
- + +
diff --git a/resource/web/event_detail.tmpl b/hal-core/resources/web/event_detail.tmpl old mode 100755 new mode 100644 similarity index 54% rename from resource/web/event_detail.tmpl rename to hal-core/resources/web/event_detail.tmpl index c0291fb6..e1466f0d --- a/resource/web/event_detail.tmpl +++ b/hal-core/resources/web/event_detail.tmpl @@ -1,4 +1,4 @@ -

Details for {{event.getName()}}

+

Details for {{event.getName()}}

@@ -6,6 +6,10 @@
# Name Type Configuration
{{.getId()}} {{.getName()}} {{.getType()}} {{.getDeviceConfig()}}
-
-
@@ -59,6 +63,21 @@
Date Data Configuration + +
+ + + +
+ +
+ + + + @@ -13,12 +17,27 @@ - + + + + + {{#event.getDeviceConfigurator().getConfiguration()}} @@ -38,7 +57,7 @@
Event ID:{{event.getId()}}
Name: {{event.getName()}}
Type:{{event.getDeviceData().getClass().getSimpleName()}}{{event.getDeviceConfig().getClass().getSimpleName()}}
Owner: {{event.getUser().getUsername()}}

State: + + + + +
+ +
+ +
{{.getNiceName()}}:
- + {{#history}} @@ -50,3 +69,11 @@ + + \ No newline at end of file diff --git a/hal-core/resources/web/favicon.ico b/hal-core/resources/web/favicon.ico new file mode 100644 index 00000000..e9d61583 Binary files /dev/null and b/hal-core/resources/web/favicon.ico differ diff --git a/resource/web/fonts/glyphicons-halflings-regular.eot b/hal-core/resources/web/fonts/glyphicons-halflings-regular.eot old mode 100755 new mode 100644 similarity index 100% rename from resource/web/fonts/glyphicons-halflings-regular.eot rename to hal-core/resources/web/fonts/glyphicons-halflings-regular.eot diff --git a/resource/web/fonts/glyphicons-halflings-regular.svg b/hal-core/resources/web/fonts/glyphicons-halflings-regular.svg similarity index 100% rename from resource/web/fonts/glyphicons-halflings-regular.svg rename to hal-core/resources/web/fonts/glyphicons-halflings-regular.svg diff --git a/resource/web/fonts/glyphicons-halflings-regular.ttf b/hal-core/resources/web/fonts/glyphicons-halflings-regular.ttf similarity index 100% rename from resource/web/fonts/glyphicons-halflings-regular.ttf rename to hal-core/resources/web/fonts/glyphicons-halflings-regular.ttf diff --git a/resource/web/fonts/glyphicons-halflings-regular.woff b/hal-core/resources/web/fonts/glyphicons-halflings-regular.woff similarity index 100% rename from resource/web/fonts/glyphicons-halflings-regular.woff rename to hal-core/resources/web/fonts/glyphicons-halflings-regular.woff diff --git a/resource/web/fonts/glyphicons-halflings-regular.woff2 b/hal-core/resources/web/fonts/glyphicons-halflings-regular.woff2 old mode 100755 new mode 100644 similarity index 100% rename from resource/web/fonts/glyphicons-halflings-regular.woff2 rename to hal-core/resources/web/fonts/glyphicons-halflings-regular.woff2 diff --git a/hal-core/resources/web/img/favicon.svg b/hal-core/resources/web/img/favicon.svg new file mode 100644 index 00000000..bb6996a5 --- /dev/null +++ b/hal-core/resources/web/img/favicon.svg @@ -0,0 +1,4 @@ + + + + diff --git a/resource/web/img/lightbulb_off.svg b/hal-core/resources/web/img/lightbulb_off.svg old mode 100755 new mode 100644 similarity index 100% rename from resource/web/img/lightbulb_off.svg rename to hal-core/resources/web/img/lightbulb_off.svg diff --git a/resource/web/img/lightbulb_on.svg b/hal-core/resources/web/img/lightbulb_on.svg old mode 100755 new mode 100644 similarity index 100% rename from resource/web/img/lightbulb_on.svg rename to hal-core/resources/web/img/lightbulb_on.svg diff --git a/resource/web/img/temperature.svg b/hal-core/resources/web/img/temperature.svg old mode 100755 new mode 100644 similarity index 100% rename from resource/web/img/temperature.svg rename to hal-core/resources/web/img/temperature.svg diff --git a/hal-core/resources/web/js/hal.js b/hal-core/resources/web/js/hal.js new file mode 100644 index 00000000..e731b2e7 --- /dev/null +++ b/hal-core/resources/web/js/hal.js @@ -0,0 +1,214 @@ +// -------------------------------------------------------- +// Autostart +// -------------------------------------------------------- + +"use strict"; + +$(function(){ + $(".toggle-switch").bootstrapSwitch({inverse: true, size: "mini"}); + + $(".timestamp").relTimestamp(); +}); + +// -------------------------------------------------------- +// JQuery helper functions +// -------------------------------------------------------- + +// $.attr() # returns all attributes of an element +(function(old) { + $.fn.attr = function() { + if(arguments.length === 0) { + if(this.length === 0) { + return null; + } + + let obj = {}; + $.each(this[0].attributes, function() { + if(this.specified) { + obj[this.name] = this.value; + } + }); + return obj; + } + + return old.apply(this, arguments); + }; +})($.fn.attr); + +// -------------------------------------------------------- +// Timestamps +// -------------------------------------------------------- + +// Converts all timestamps to human readable time and date +$.fn.relTimestamp = function() { + return this.each(function() { + let timestamp = parseInt($(this).text()); + + $(this).text(getRelTimestamp(timestamp)); + return this; + }); +}; + +// Converts all timestamps to human readable time and date +function getRelTimestamp(timestamp) { + if (timestamp == null) + return ""; + + let timestampNow = Date.now(); + let timeDiff = timestampNow - timestamp; + + if(timeDiff < 10 * 60 * 1000) // less than 10 min + return moment(timestamp).fromNow(); + else if(timeDiff < 24 * 60 * 60 * 1000) // less than 24 hours + return moment(timestamp).fromNow() + " ("+moment(timestamp).format("HH:mm")+")"; + else + return moment(timestamp).format("YYYY-MM-DD HH:mm"); +} + +// -------------------------------------------------------- +// Chart functions +// -------------------------------------------------------- + +function createChart(elementId, url, updateTime=-1){ + let tickConf = {count: 20}; + if (updateTime < 60*60*1000) + tickConf['format'] = '%H:%M'; + else if (updateTime < 24*60*60*1000) + tickConf['format'] = '%Y-%m-%d %H:%M'; + else + tickConf['format'] = '%Y-%m-%d'; + + + var chart = c3.generate({ + bindto: elementId, + data: {json: []}, // set empty data, data will be loaded later + axis : { + x : { + type : 'timeseries', + label: 'Timestamp', + tick: tickConf, + }, + y: { + label: 'Power (kWh)', + min: 0, + }, + y2: { + show: true, + label: 'Temperature (C)', + min: 0, + } + }, + grid: { + y: {show: true} + }, + point: { + show: false + } + }); + + updateChart(chart, url, updateTime); + $(window).focus(function(e) { + updateChart(chart, url); + }); +} +function updateChart(chart, url, updateTime=-1){ + console.log('Updating chart: ' + chart.element.id); + + $.getJSON(url, function(json) { + chart.load(getChartData(json)); + }); + + if (updateTime > 0) { + setTimeout(function() { + updateChart(chart, url, updateTime); + }, updateTime); + } +} +function getChartData(json){ + let dataXaxis = {}; + let dataYaxis = {}; + let data = []; + let labels = []; + + json.forEach(function(sensor, i) { + var index = 'data' + i; + labels[index] = sensor.user + ': ' + sensor.name; + dataXaxis[index] = 'data' + i + 'x'; + data.push([index + 'x'].concat(sensor.aggregate.timestamps)); + data.push([index].concat(sensor.aggregate.data)); + + if (sensor.type == 'PowerConsumptionSensorData') + dataYaxis[index] = 'y'; + else //if (sensor.type == "TemperatureSensorData") + dataYaxis[index] = 'y2'; + }); + + return { + xs: dataXaxis, + columns: data, + names: labels, + type: 'spline', + axes: dataYaxis, + unload: true, + }; +} + +// -------------------------------------------------------- +// Dynamic forms +// -------------------------------------------------------- + +var dynamicConf = {}; + +function initDynamicModalForm(modalId, formTemplateId = null, templateID = null){ + // read in all configurations into global variable (to skip naming issues) + if (formTemplateId != null) { + dynamicConf[formTemplateId] = []; + $("#" + templateID + " div").each(function(){ + dynamicConf[formTemplateId][$(this).prop("id")] = $(this).html(); + }); + + // Update dynamic inputs + $("#" + modalId + " select[name=type]").change(function(){ + $("#" + modalId + " #" + formTemplateId).html(dynamicConf[formTemplateId][$(this).val()]); + }); + } + + // click event + $("#" + modalId).on('show.bs.modal', function (event) { + let button = $(event.relatedTarget); + let modal = $(this); + + modal.find(" input, select").val('').change(); // Reset all inputs + + // Set dynamic form data + $.each(button.attr(), function(fieldName, value) { + if(fieldName.startsWith("data-")) { + fieldName = fieldName.substring(5); // remove prefix data- + + // Case-insensitive search + var input = modal.find("input, select").filter(function() { + if (this.name.toLowerCase() == fieldName) { + if (this.type == "hidden" && modal.find("input[type=checkbox][name=" + fieldName + "]").length > 0) + return false; // Workaround for the default(false) boolean input + return true; + } + return false; + }); + + if (input.length > 0) { + if (input.prop("type") == "checkbox") { // special handling for checkboxes + input.prop("value", "true"); + input.prop("checked", value == "true"); + + if (modal.find("input[type=hidden][name=" + fieldName + "]") == null) { + // Add default false value as a unchecked checkbox is not included in the post + input.parent().prepend(""); + } + } else { + input.val(value).change(); + } + } + } + }); + }); +} \ No newline at end of file diff --git a/hal-core/resources/web/js/hal_alert.js b/hal-core/resources/web/js/hal_alert.js new file mode 100644 index 00000000..e2e9baa7 --- /dev/null +++ b/hal-core/resources/web/js/hal_alert.js @@ -0,0 +1,86 @@ +// -------------------------------------------------------- +// Autostart +// -------------------------------------------------------- + +"use strict"; + +var alertDivId = "alert-container" +var alertTemplate = { + ERROR: ` +
+ + +   + +
`, + WARNING: ` +
+ + +   + +
`, + SUCCESS: ` +
+ + +   + +
`, + INFO: ` +
+ + +   + +
` +} + +$(function(){ + updateAlerts(); + + setInterval(function() { + updateAlerts(); + }, 3000); // 3 sec +}); + +function updateAlerts() { + fetch('/api/alert?action=poll') + .then(response => response.json()) + .then(data => { + data.forEach(alert => { + var alertElement = $("#alert-id-" + alert.id); + + if (alertElement.length <= 0) { + alertElement = $(alertTemplate[alert.level]); + $("#" + alertDivId).append(alertElement); + + alertElement.attr("id", "alert-id-" + alert.id); + alertElement.data("alert-id", alert.id); + alertElement.find(".close").click(dismissEvent); + } + + alertElement.find(".alert-title").html(alert.title); + alertElement.find(".alert-description").html(alert.description); + alertElement.find(".timestamp").relTimestamp(); + }); + }); +} + +function dismissEvent(e) { + dismissAlert($(e.target).parent().parent().data("alert-id")); +} +function dismissAlert(id) { + fetch('/api/alert?action=dismiss&id=' + id) + .then(response => response.json()) + .then(data => { + }); +} \ No newline at end of file diff --git a/hal-core/resources/web/js/hal_map.js b/hal-core/resources/web/js/hal_map.js new file mode 100644 index 00000000..d05f22a4 --- /dev/null +++ b/hal-core/resources/web/js/hal_map.js @@ -0,0 +1,306 @@ +"use strict"; + +var svg; +var data = { + rooms: [], + sensors: [], + events: [] +}; +var editModeEnabled = false; + +$(function(){ + // ------------------------------------------ + // Setup map + // ------------------------------------------ + + svg = SVG('map'); + + // Initialize events + + $("#button-edit").click(function() { + editMode(true); + }); + $("#button-save").click(function() { + saveMap(); + editMode(false); + fetchData(drawMap); + }); + $("#button-cancel").click(function() { + editMode(false); + fetchData(drawMap); + }); + + // Initialize background image uploader + + $("#button-bg-edit").click(function() { + // Reset modal + $('#bg-file-input').parent().show(); + if ($("#file_input").prop("jFiler") != null) + $("#file_input").prop("jFiler").reset(); + $('#bg-file-progress').parent().hide(); + $('#bgUploadModal').modal('show'); + }); + $('#bg-file-input').filer({ + limit: 1, + extensions: ['jpg','png','svg','gif'], + maxSize: 3, // in MB + uploadFile: { + url: "", + type: 'POST', + enctype: 'multipart/form-data', + beforeSend: function(){ + $('#bg-file-input').parent().hide(); + $('#bg-file-progress').parent().show(); + }, + success: function(data, el){ + $('#bgUploadModal').modal('hide'); + drawMap(); + }, + error: function(el){ + $("#bg-file-progress").addClass("progress-bar-danger"); + }, + onProgress: function(t){ + $("#bg-file-progress").css("width", t + "%"); + }, + } + }); + + // ------------------------------------------ + // Start draw loop + // ------------------------------------------ + + fetchData(drawMap); + + setInterval(function() { + if (editModeEnabled == false) { + fetchData(drawMap); + } + }, 3000); // 3 sec + //}, 10000); // 10 sec + +}); + +// ---------------------------------------------- +// Events +// ---------------------------------------------- + +function editMode(enable){ + if (editModeEnabled == enable) { + return; + } + + editModeEnabled = enable; + + if (editModeEnabled) { + $('.edit-mode').show(); + $('.view-mode').hide(); + $('#map').css('border-color', '#6eb16e'); + + svg.select('.draggable').draggable(true); + //svg.select('.resizable').on('click', selectEvent, false); + svg.select('.resizable').selectize({ + points: ['rt', 'lb', 'rb'], // Add selection points on the corners + rotationPoint: false + }).resize() + } else { + $('.edit-mode').hide(); + $('.view-mode').show(); + $('#map').css('border-color', ''); + + svg.select('.draggable').draggable(false); + svg.select('resizable').selectize(false); + } +} + +function beforeDragEvent(e) { + if (editModeEnabled == false) { + e.preventDefault(); // Prevent drag + } +} + +function selectEvent(e) { + if (editModeEnabled == true) { + e.target.selectize({ + points: ['rt', 'lb', 'rb'], // Add selection points on the corners + rotationPoint: false + }).resize(); + } +} + +// -------------------------------------- +// Draw +// -------------------------------------- + +function drawMap() { + // Reset map + svg.clear(); + + // Background + + if (svg.select(".bg-image").length() <= 0) { + var bgImage = svg.image("?bgimage").addClass("bg-image") + .x(0) + .y(0) + .width("100%") + .height("100%"); + } + + // Rooms + + if (data.rooms != null) { + $.each(data.rooms, function(i, room) { + svg.select("#room-" + room.id).remove(); + + var group = svg.group(); + + group.text(room.name).move(5, 5).fill('#999'); + var rect = group.rect(room.map.width, room.map.height); + setAlertStyle(rect, (room.alert == null ? null : room.alert.level)); + rect.addClass("resizable"); + + group.addClass("room") + .attr("id", "room-" + room.id) + .attr("room-id", room.id) + .x(room.map.x) + .y(room.map.y) + .addClass("draggable"); + }); + } + + // Sensors + + if (data.sensors != null) { + $.each(data.sensors, function(i, sensor) { + svg.select("#sensor-" + sensor.id).remove(); + + var group = svg.group(); + group.element('title').words(sensor.name); + + group.text(sensor.data.valueStr).move(45, 15).fill('#999'); + group.image("/img/temperature.svg").size(50, 50); + + group.addClass("sensor") + .attr("id", "sensor-" + sensor.id) + .attr("sensor-id", sensor.id) + .x(sensor.map.x) + .y(sensor.map.y) + .addClass("draggable"); + }); + } + + // Events + + if (data.events != null) { + $.each(data.events, function(i, event) { + svg.select("#event-" + event.id).remove(); + + var group = svg.group(); + group.element('title').words(event.name); + + var img = "/img/lightbulb_off.svg"; + if (event.data.valueStr == "ON") + img = "/img/lightbulb_on.svg"; + group.image(img).size(50, 50); + + group.addClass("event") + .attr("id", "event-" + event.id) + .attr("event-id", event.id) + .x(event.map.x) + .y(event.map.y) + .addClass("draggable"); + }); + } +} + +// ---------------------------------------------- +// Load and Store data +// ---------------------------------------------- + +async function fetchData(callback) { + await fetch('/api/room') + .then(response => response.json()) + .then(json => { + data.rooms = json; + }) + + await fetch('/api/sensor') + .then(response => response.json()) + .then(json => { + data.sensors = json; + }) + + await fetch('/api/event') + .then(response => response.json()) + .then(json => { + data.events = json; + }) + + callback(); +} + +function saveMap(){ + svg.select(".room").each(function(){ + saveDevice(this, "room", "room-id"); + }); + svg.select(".sensor").each(function(){ + saveDevice(this, "sensor", "sensor-id"); + }); + svg.select(".event").each(function(){ + saveDevice(this, "event", "event-id"); + }); +} +function saveDevice(element, type, id) { + var data = { + action: "save", + id: element.attr(id), + type: type, + x: element.x(), + y: element.y() + }; + + var resizable = element.select(".resizable"); + if (resizable.length() > 0) { + data.width = resizable.get(0).width(); + data.height = resizable.get(0).height(); + } + + $.ajax({ + async: false, + dataType: "json", + url: "/api/map?", + data: data + }); +} + +// ---------------------------------------------- +// Colors +// ---------------------------------------------- + +function setAlertStyle(target, level=null) { + target.addClass("pulse-border"); + target.fill('none'); + + switch(level) { + case "ERROR": + target.stroke({opacity: 1, color: '#f00'}); + break; + case "WARNING": + target.stroke({opacity: 1, color: '#ffa500'}); + break; + case "SUCCESS": + target.stroke({opacity: 1, color: '#90EE90'}); + break; + case "INFO": + target.stroke({opacity: 1, color: '#87CEFA'}); + break; + + default: + target.removeClass("pulse-border"); + target.stroke({ + color: '#000', + opacity: 0.6, + width: 3 + });; + break; + } +} \ No newline at end of file diff --git a/hal-core/resources/web/js/lib/bootstrap-colorpicker.LICENSE b/hal-core/resources/web/js/lib/bootstrap-colorpicker.LICENSE new file mode 100644 index 00000000..bc6fc511 --- /dev/null +++ b/hal-core/resources/web/js/lib/bootstrap-colorpicker.LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2017 Javi Aguilar + +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. diff --git a/hal-core/resources/web/js/lib/bootstrap-colorpicker.LICENSE.txt b/hal-core/resources/web/js/lib/bootstrap-colorpicker.LICENSE.txt new file mode 100644 index 00000000..bc6fc511 --- /dev/null +++ b/hal-core/resources/web/js/lib/bootstrap-colorpicker.LICENSE.txt @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2017 Javi Aguilar + +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. diff --git a/hal-core/resources/web/js/lib/bootstrap-colorpicker.js b/hal-core/resources/web/js/lib/bootstrap-colorpicker.js new file mode 100644 index 00000000..e2fd15da --- /dev/null +++ b/hal-core/resources/web/js/lib/bootstrap-colorpicker.js @@ -0,0 +1,6252 @@ +/*! + * Bootstrap Colorpicker - Bootstrap Colorpicker is a modular color picker plugin for Bootstrap 4. + * @package bootstrap-colorpicker + * @version v3.2.0 + * @license MIT + * @link https://itsjavi.com/bootstrap-colorpicker/ + * @link https://github.com/itsjavi/bootstrap-colorpicker.git + */ +(function webpackUniversalModuleDefinition(root, factory) { + if(typeof exports === 'object' && typeof module === 'object') + module.exports = factory(require("jquery")); + else if(typeof define === 'function' && define.amd) + define("bootstrap-colorpicker", ["jquery"], factory); + else if(typeof exports === 'object') + exports["bootstrap-colorpicker"] = factory(require("jquery")); + else + root["bootstrap-colorpicker"] = factory(root["jQuery"]); +})(window, function(__WEBPACK_EXTERNAL_MODULE__0__) { +return /******/ (function(modules) { // webpackBootstrap +/******/ // The module cache +/******/ var installedModules = {}; +/******/ +/******/ // The require function +/******/ function __webpack_require__(moduleId) { +/******/ +/******/ // Check if module is in cache +/******/ if(installedModules[moduleId]) { +/******/ return installedModules[moduleId].exports; +/******/ } +/******/ // Create a new module (and put it into the cache) +/******/ var module = installedModules[moduleId] = { +/******/ i: moduleId, +/******/ l: false, +/******/ exports: {} +/******/ }; +/******/ +/******/ // Execute the module function +/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); +/******/ +/******/ // Flag the module as loaded +/******/ module.l = true; +/******/ +/******/ // Return the exports of the module +/******/ return module.exports; +/******/ } +/******/ +/******/ +/******/ // expose the modules object (__webpack_modules__) +/******/ __webpack_require__.m = modules; +/******/ +/******/ // expose the module cache +/******/ __webpack_require__.c = installedModules; +/******/ +/******/ // define getter function for harmony exports +/******/ __webpack_require__.d = function(exports, name, getter) { +/******/ if(!__webpack_require__.o(exports, name)) { +/******/ Object.defineProperty(exports, name, { enumerable: true, get: getter }); +/******/ } +/******/ }; +/******/ +/******/ // define __esModule on exports +/******/ __webpack_require__.r = function(exports) { +/******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) { +/******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' }); +/******/ } +/******/ Object.defineProperty(exports, '__esModule', { value: true }); +/******/ }; +/******/ +/******/ // create a fake namespace object +/******/ // mode & 1: value is a module id, require it +/******/ // mode & 2: merge all properties of value into the ns +/******/ // mode & 4: return value when already ns object +/******/ // mode & 8|1: behave like require +/******/ __webpack_require__.t = function(value, mode) { +/******/ if(mode & 1) value = __webpack_require__(value); +/******/ if(mode & 8) return value; +/******/ if((mode & 4) && typeof value === 'object' && value && value.__esModule) return value; +/******/ var ns = Object.create(null); +/******/ __webpack_require__.r(ns); +/******/ Object.defineProperty(ns, 'default', { enumerable: true, value: value }); +/******/ if(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key)); +/******/ return ns; +/******/ }; +/******/ +/******/ // getDefaultExport function for compatibility with non-harmony modules +/******/ __webpack_require__.n = function(module) { +/******/ var getter = module && module.__esModule ? +/******/ function getDefault() { return module['default']; } : +/******/ function getModuleExports() { return module; }; +/******/ __webpack_require__.d(getter, 'a', getter); +/******/ return getter; +/******/ }; +/******/ +/******/ // Object.prototype.hasOwnProperty.call +/******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); }; +/******/ +/******/ // __webpack_public_path__ +/******/ __webpack_require__.p = ""; +/******/ +/******/ +/******/ // Load entry module and return exports +/******/ return __webpack_require__(__webpack_require__.s = 7); +/******/ }) +/************************************************************************/ +/******/ ([ +/* 0 */ +/***/ (function(module, exports) { + +module.exports = __WEBPACK_EXTERNAL_MODULE__0__; + +/***/ }), +/* 1 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); + +var _jquery = __webpack_require__(0); + +var _jquery2 = _interopRequireDefault(_jquery); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + +/** + * Colorpicker extension class. + */ +var Extension = function () { + /** + * @param {Colorpicker} colorpicker + * @param {Object} options + */ + function Extension(colorpicker) { + var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; + + _classCallCheck(this, Extension); + + /** + * The colorpicker instance + * @type {Colorpicker} + */ + this.colorpicker = colorpicker; + /** + * Extension options + * + * @type {Object} + */ + this.options = options; + + if (!(this.colorpicker.element && this.colorpicker.element.length)) { + throw new Error('Extension: this.colorpicker.element is not valid'); + } + + this.colorpicker.element.on('colorpickerCreate.colorpicker-ext', _jquery2.default.proxy(this.onCreate, this)); + this.colorpicker.element.on('colorpickerDestroy.colorpicker-ext', _jquery2.default.proxy(this.onDestroy, this)); + this.colorpicker.element.on('colorpickerUpdate.colorpicker-ext', _jquery2.default.proxy(this.onUpdate, this)); + this.colorpicker.element.on('colorpickerChange.colorpicker-ext', _jquery2.default.proxy(this.onChange, this)); + this.colorpicker.element.on('colorpickerInvalid.colorpicker-ext', _jquery2.default.proxy(this.onInvalid, this)); + this.colorpicker.element.on('colorpickerShow.colorpicker-ext', _jquery2.default.proxy(this.onShow, this)); + this.colorpicker.element.on('colorpickerHide.colorpicker-ext', _jquery2.default.proxy(this.onHide, this)); + this.colorpicker.element.on('colorpickerEnable.colorpicker-ext', _jquery2.default.proxy(this.onEnable, this)); + this.colorpicker.element.on('colorpickerDisable.colorpicker-ext', _jquery2.default.proxy(this.onDisable, this)); + } + + /** + * Function called every time a new color needs to be created. + * Return false to skip this resolver and continue with other extensions' ones + * or return anything else to consider the color resolved. + * + * @param {ColorItem|String|*} color + * @param {boolean} realColor if true, the color should resolve into a real (not named) color code + * @return {ColorItem|String|*} + */ + + + _createClass(Extension, [{ + key: 'resolveColor', + value: function resolveColor(color) { + var realColor = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true; + + return false; + } + + /** + * Method called after the colorpicker is created + * + * @listens Colorpicker#colorpickerCreate + * @param {Event} event + */ + + }, { + key: 'onCreate', + value: function onCreate(event) {} + // to be extended + + + /** + * Method called after the colorpicker is destroyed + * + * @listens Colorpicker#colorpickerDestroy + * @param {Event} event + */ + + }, { + key: 'onDestroy', + value: function onDestroy(event) { + this.colorpicker.element.off('.colorpicker-ext'); + } + + /** + * Method called after the colorpicker is updated + * + * @listens Colorpicker#colorpickerUpdate + * @param {Event} event + */ + + }, { + key: 'onUpdate', + value: function onUpdate(event) {} + // to be extended + + + /** + * Method called after the colorpicker color is changed + * + * @listens Colorpicker#colorpickerChange + * @param {Event} event + */ + + }, { + key: 'onChange', + value: function onChange(event) {} + // to be extended + + + /** + * Method called when the colorpicker color is invalid + * + * @listens Colorpicker#colorpickerInvalid + * @param {Event} event + */ + + }, { + key: 'onInvalid', + value: function onInvalid(event) {} + // to be extended + + + /** + * Method called after the colorpicker is hidden + * + * @listens Colorpicker#colorpickerHide + * @param {Event} event + */ + + }, { + key: 'onHide', + value: function onHide(event) {} + // to be extended + + + /** + * Method called after the colorpicker is shown + * + * @listens Colorpicker#colorpickerShow + * @param {Event} event + */ + + }, { + key: 'onShow', + value: function onShow(event) {} + // to be extended + + + /** + * Method called after the colorpicker is disabled + * + * @listens Colorpicker#colorpickerDisable + * @param {Event} event + */ + + }, { + key: 'onDisable', + value: function onDisable(event) {} + // to be extended + + + /** + * Method called after the colorpicker is enabled + * + * @listens Colorpicker#colorpickerEnable + * @param {Event} event + */ + + }, { + key: 'onEnable', + value: function onEnable(event) { + // to be extended + } + }]); + + return Extension; +}(); + +exports.default = Extension; +module.exports = exports.default; + +/***/ }), +/* 2 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.ColorItem = exports.HSVAColor = undefined; + +var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); /** + * Color manipulation class, specific for Bootstrap Colorpicker + */ + + +var _color = __webpack_require__(16); + +var _color2 = _interopRequireDefault(_color); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + +/** + * HSVA color data class, containing the hue, saturation, value and alpha + * information. + */ +var HSVAColor = function () { + /** + * @param {number|int} h + * @param {number|int} s + * @param {number|int} v + * @param {number|int} a + */ + function HSVAColor(h, s, v, a) { + _classCallCheck(this, HSVAColor); + + this.h = isNaN(h) ? 0 : h; + this.s = isNaN(s) ? 0 : s; + this.v = isNaN(v) ? 0 : v; + this.a = isNaN(h) ? 1 : a; + } + + _createClass(HSVAColor, [{ + key: 'toString', + value: function toString() { + return this.h + ', ' + this.s + '%, ' + this.v + '%, ' + this.a; + } + }]); + + return HSVAColor; +}(); + +/** + * HSVA color manipulation + */ + + +var ColorItem = function () { + _createClass(ColorItem, [{ + key: 'api', + + + /** + * Applies a method of the QixColor API and returns a new Color object or + * the return value of the method call. + * + * If no argument is provided, the internal QixColor object is returned. + * + * @param {String} fn QixColor function name + * @param args QixColor function arguments + * @example let darkerColor = color.api('darken', 0.25); + * @example let luminosity = color.api('luminosity'); + * @example color = color.api('negate'); + * @example let qColor = color.api().negate(); + * @returns {ColorItem|QixColor|*} + */ + value: function api(fn) { + for (var _len = arguments.length, args = Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) { + args[_key - 1] = arguments[_key]; + } + + if (arguments.length === 0) { + return this._color; + } + + var result = this._color[fn].apply(this._color, args); + + if (!(result instanceof _color2.default)) { + // return result of the method call + return result; + } + + return new ColorItem(result, this.format); + } + + /** + * Returns the original ColorItem constructor data, + * plus a 'valid' flag to know if it's valid or not. + * + * @returns {{color: *, format: String, valid: boolean}} + */ + + }, { + key: 'original', + get: function get() { + return this._original; + } + + /** + * @param {ColorItem|HSVAColor|QixColor|String|*|null} color Color data + * @param {String|null} format Color model to convert to by default. Supported: 'rgb', 'hsl', 'hex'. + */ + + }], [{ + key: 'HSVAColor', + + + /** + * Returns the HSVAColor class + * + * @static + * @example let colorData = new ColorItem.HSVAColor(360, 100, 100, 1); + * @returns {HSVAColor} + */ + get: function get() { + return HSVAColor; + } + }]); + + function ColorItem() { + var color = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : null; + var format = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null; + + _classCallCheck(this, ColorItem); + + this.replace(color, format); + } + + /** + * Replaces the internal QixColor object with a new one. + * This also replaces the internal original color data. + * + * @param {ColorItem|HSVAColor|QixColor|String|*|null} color Color data to be parsed (if needed) + * @param {String|null} format Color model to convert to by default. Supported: 'rgb', 'hsl', 'hex'. + * @example color.replace('rgb(255,0,0)', 'hsl'); + * @example color.replace(hsvaColorData); + */ + + + _createClass(ColorItem, [{ + key: 'replace', + value: function replace(color) { + var format = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null; + + format = ColorItem.sanitizeFormat(format); + + /** + * @type {{color: *, format: String}} + * @private + */ + this._original = { + color: color, + format: format, + valid: true + }; + /** + * @type {QixColor} + * @private + */ + this._color = ColorItem.parse(color); + + if (this._color === null) { + this._color = (0, _color2.default)(); + this._original.valid = false; + return; + } + + /** + * @type {*|string} + * @private + */ + this._format = format ? format : ColorItem.isHex(color) ? 'hex' : this._color.model; + } + + /** + * Parses the color returning a Qix Color object or null if cannot be + * parsed. + * + * @param {ColorItem|HSVAColor|QixColor|String|*|null} color Color data + * @example let qColor = ColorItem.parse('rgb(255,0,0)'); + * @static + * @returns {QixColor|null} + */ + + }, { + key: 'isValid', + + + /** + * Returns true if the color is valid, false if not. + * + * @returns {boolean} + */ + value: function isValid() { + return this._original.valid === true; + } + + /** + * Hue value from 0 to 360 + * + * @returns {int} + */ + + }, { + key: 'setHueRatio', + + + /** + * Sets the hue ratio, where 1.0 is 0, 0.5 is 180 and 0.0 is 360. + * + * @ignore + * @param {number} h Ratio from 1.0 to 0.0 + */ + value: function setHueRatio(h) { + this.hue = (1 - h) * 360; + } + + /** + * Sets the saturation value + * + * @param {int} value Integer from 0 to 100 + */ + + }, { + key: 'setSaturationRatio', + + + /** + * Sets the saturation ratio, where 1.0 is 100 and 0.0 is 0. + * + * @ignore + * @param {number} s Ratio from 0.0 to 1.0 + */ + value: function setSaturationRatio(s) { + this.saturation = s * 100; + } + + /** + * Sets the 'value' channel value + * + * @param {int} value Integer from 0 to 100 + */ + + }, { + key: 'setValueRatio', + + + /** + * Sets the value ratio, where 1.0 is 0 and 0.0 is 100. + * + * @ignore + * @param {number} v Ratio from 1.0 to 0.0 + */ + value: function setValueRatio(v) { + this.value = (1 - v) * 100; + } + + /** + * Sets the alpha value. It will be rounded to 2 decimals. + * + * @param {int} value Float from 0.0 to 1.0 + */ + + }, { + key: 'setAlphaRatio', + + + /** + * Sets the alpha ratio, where 1.0 is 0.0 and 0.0 is 1.0. + * + * @ignore + * @param {number} a Ratio from 1.0 to 0.0 + */ + value: function setAlphaRatio(a) { + this.alpha = 1 - a; + } + + /** + * Sets the default color format + * + * @param {String} value Supported: 'rgb', 'hsl', 'hex' + */ + + }, { + key: 'isDesaturated', + + + /** + * Returns true if the saturation value is zero, false otherwise + * + * @returns {boolean} + */ + value: function isDesaturated() { + return this.saturation === 0; + } + + /** + * Returns true if the alpha value is zero, false otherwise + * + * @returns {boolean} + */ + + }, { + key: 'isTransparent', + value: function isTransparent() { + return this.alpha === 0; + } + + /** + * Returns true if the alpha value is numeric and less than 1, false otherwise + * + * @returns {boolean} + */ + + }, { + key: 'hasTransparency', + value: function hasTransparency() { + return this.hasAlpha() && this.alpha < 1; + } + + /** + * Returns true if the alpha value is numeric, false otherwise + * + * @returns {boolean} + */ + + }, { + key: 'hasAlpha', + value: function hasAlpha() { + return !isNaN(this.alpha); + } + + /** + * Returns a new HSVAColor object, based on the current color + * + * @returns {HSVAColor} + */ + + }, { + key: 'toObject', + value: function toObject() { + return new HSVAColor(this.hue, this.saturation, this.value, this.alpha); + } + + /** + * Alias of toObject() + * + * @returns {HSVAColor} + */ + + }, { + key: 'toHsva', + value: function toHsva() { + return this.toObject(); + } + + /** + * Returns a new HSVAColor object with the ratio values (from 0.0 to 1.0), + * based on the current color. + * + * @ignore + * @returns {HSVAColor} + */ + + }, { + key: 'toHsvaRatio', + value: function toHsvaRatio() { + return new HSVAColor(this.hue / 360, this.saturation / 100, this.value / 100, this.alpha); + } + + /** + * Converts the current color to its string representation, + * using the internal format of this instance. + * + * @returns {String} + */ + + }, { + key: 'toString', + value: function toString() { + return this.string(); + } + + /** + * Converts the current color to its string representation, + * using the given format. + * + * @param {String|null} format Format to convert to. If empty or null, the internal format will be used. + * @returns {String} + */ + + }, { + key: 'string', + value: function string() { + var format = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : null; + + format = ColorItem.sanitizeFormat(format ? format : this.format); + + if (!format) { + return this._color.round().string(); + } + + if (this._color[format] === undefined) { + throw new Error('Unsupported color format: \'' + format + '\''); + } + + var str = this._color[format](); + + return str.round ? str.round().string() : str; + } + + /** + * Returns true if the given color values equals this one, false otherwise. + * The format is not compared. + * If any of the colors is invalid, the result will be false. + * + * @param {ColorItem|HSVAColor|QixColor|String|*|null} color Color data + * + * @returns {boolean} + */ + + }, { + key: 'equals', + value: function equals(color) { + color = color instanceof ColorItem ? color : new ColorItem(color); + + if (!color.isValid() || !this.isValid()) { + return false; + } + + return this.hue === color.hue && this.saturation === color.saturation && this.value === color.value && this.alpha === color.alpha; + } + + /** + * Creates a copy of this instance + * + * @returns {ColorItem} + */ + + }, { + key: 'getClone', + value: function getClone() { + return new ColorItem(this._color, this.format); + } + + /** + * Creates a copy of this instance, only copying the hue value, + * and setting the others to its max value. + * + * @returns {ColorItem} + */ + + }, { + key: 'getCloneHueOnly', + value: function getCloneHueOnly() { + return new ColorItem([this.hue, 100, 100, 1], this.format); + } + + /** + * Creates a copy of this instance setting the alpha to the max. + * + * @returns {ColorItem} + */ + + }, { + key: 'getCloneOpaque', + value: function getCloneOpaque() { + return new ColorItem(this._color.alpha(1), this.format); + } + + /** + * Converts the color to a RGB string + * + * @returns {String} + */ + + }, { + key: 'toRgbString', + value: function toRgbString() { + return this.string('rgb'); + } + + /** + * Converts the color to a Hexadecimal string + * + * @returns {String} + */ + + }, { + key: 'toHexString', + value: function toHexString() { + return this.string('hex'); + } + + /** + * Converts the color to a HSL string + * + * @returns {String} + */ + + }, { + key: 'toHslString', + value: function toHslString() { + return this.string('hsl'); + } + + /** + * Returns true if the color is dark, false otherwhise. + * This is useful to decide a text color. + * + * @returns {boolean} + */ + + }, { + key: 'isDark', + value: function isDark() { + return this._color.isDark(); + } + + /** + * Returns true if the color is light, false otherwhise. + * This is useful to decide a text color. + * + * @returns {boolean} + */ + + }, { + key: 'isLight', + value: function isLight() { + return this._color.isLight(); + } + + /** + * Generates a list of colors using the given hue-based formula or the given array of hue values. + * Hue formulas can be extended using ColorItem.colorFormulas static property. + * + * @param {String|Number[]} formula Examples: 'complementary', 'triad', 'tetrad', 'splitcomplement', [180, 270] + * @example let colors = color.generate('triad'); + * @example let colors = color.generate([45, 80, 112, 200]); + * @returns {ColorItem[]} + */ + + }, { + key: 'generate', + value: function generate(formula) { + var hues = []; + + if (Array.isArray(formula)) { + hues = formula; + } else if (!ColorItem.colorFormulas.hasOwnProperty(formula)) { + throw new Error('No color formula found with the name \'' + formula + '\'.'); + } else { + hues = ColorItem.colorFormulas[formula]; + } + + var colors = [], + mainColor = this._color, + format = this.format; + + hues.forEach(function (hue) { + var levels = [hue ? (mainColor.hue() + hue) % 360 : mainColor.hue(), mainColor.saturationv(), mainColor.value(), mainColor.alpha()]; + + colors.push(new ColorItem(levels, format)); + }); + + return colors; + } + }, { + key: 'hue', + get: function get() { + return this._color.hue(); + } + + /** + * Saturation value from 0 to 100 + * + * @returns {int} + */ + , + + + /** + * Sets the hue value + * + * @param {int} value Integer from 0 to 360 + */ + set: function set(value) { + this._color = this._color.hue(value); + } + }, { + key: 'saturation', + get: function get() { + return this._color.saturationv(); + } + + /** + * Value channel value from 0 to 100 + * + * @returns {int} + */ + , + set: function set(value) { + this._color = this._color.saturationv(value); + } + }, { + key: 'value', + get: function get() { + return this._color.value(); + } + + /** + * Alpha value from 0.0 to 1.0 + * + * @returns {number} + */ + , + set: function set(value) { + this._color = this._color.value(value); + } + }, { + key: 'alpha', + get: function get() { + var a = this._color.alpha(); + + return isNaN(a) ? 1 : a; + } + + /** + * Default color format to convert to when calling toString() or string() + * + * @returns {String} 'rgb', 'hsl', 'hex' or '' + */ + , + set: function set(value) { + // 2 decimals max + this._color = this._color.alpha(Math.round(value * 100) / 100); + } + }, { + key: 'format', + get: function get() { + return this._format ? this._format : this._color.model; + }, + set: function set(value) { + this._format = ColorItem.sanitizeFormat(value); + } + }], [{ + key: 'parse', + value: function parse(color) { + if (color instanceof _color2.default) { + return color; + } + + if (color instanceof ColorItem) { + return color._color; + } + + var format = null; + + if (color instanceof HSVAColor) { + color = [color.h, color.s, color.v, isNaN(color.a) ? 1 : color.a]; + } else { + color = ColorItem.sanitizeString(color); + } + + if (color === null) { + return null; + } + + if (Array.isArray(color)) { + format = 'hsv'; + } + + try { + return (0, _color2.default)(color, format); + } catch (e) { + return null; + } + } + + /** + * Sanitizes a color string, adding missing hash to hexadecimal colors + * and converting 'transparent' to a color code. + * + * @param {String|*} str Color string + * @example let colorStr = ColorItem.sanitizeString('ffaa00'); + * @static + * @returns {String|*} + */ + + }, { + key: 'sanitizeString', + value: function sanitizeString(str) { + if (!(typeof str === 'string' || str instanceof String)) { + return str; + } + + if (str.match(/^[0-9a-f]{2,}$/i)) { + return '#' + str; + } + + if (str.toLowerCase() === 'transparent') { + return '#FFFFFF00'; + } + + return str; + } + + /** + * Detects if a value is a string and a color in hexadecimal format (in any variant). + * + * @param {String} str + * @example ColorItem.isHex('rgba(0,0,0)'); // false + * @example ColorItem.isHex('ffaa00'); // true + * @example ColorItem.isHex('#ffaa00'); // true + * @static + * @returns {boolean} + */ + + }, { + key: 'isHex', + value: function isHex(str) { + if (!(typeof str === 'string' || str instanceof String)) { + return false; + } + + return !!str.match(/^#?[0-9a-f]{2,}$/i); + } + + /** + * Sanitizes a color format to one supported by web browsers. + * Returns an empty string of the format can't be recognised. + * + * @param {String|*} format + * @example ColorItem.sanitizeFormat('rgba'); // 'rgb' + * @example ColorItem.isHex('hex8'); // 'hex' + * @example ColorItem.isHex('invalid'); // '' + * @static + * @returns {String} 'rgb', 'hsl', 'hex' or ''. + */ + + }, { + key: 'sanitizeFormat', + value: function sanitizeFormat(format) { + switch (format) { + case 'hex': + case 'hex3': + case 'hex4': + case 'hex6': + case 'hex8': + return 'hex'; + case 'rgb': + case 'rgba': + case 'keyword': + case 'name': + return 'rgb'; + case 'hsl': + case 'hsla': + case 'hsv': + case 'hsva': + case 'hwb': // HWB this is supported by Qix Color, but not by browsers + case 'hwba': + return 'hsl'; + default: + return ''; + } + } + }]); + + return ColorItem; +}(); + +/** + * List of hue-based color formulas used by ColorItem.prototype.generate() + * + * @static + * @type {{complementary: number[], triad: number[], tetrad: number[], splitcomplement: number[]}} + */ + + +ColorItem.colorFormulas = { + complementary: [180], + triad: [0, 120, 240], + tetrad: [0, 90, 180, 270], + splitcomplement: [0, 72, 216] +}; + +exports.default = ColorItem; +exports.HSVAColor = HSVAColor; +exports.ColorItem = ColorItem; + +/***/ }), +/* 3 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + +/** + * @module + */ + +// adjust these values accordingly to the sass vars + +Object.defineProperty(exports, "__esModule", { + value: true +}); +var sassVars = { + 'bar_size_short': 16, + 'base_margin': 6, + 'columns': 6 +}; + +var sliderSize = sassVars.bar_size_short * sassVars.columns + sassVars.base_margin * (sassVars.columns - 1); + +/** + * Colorpicker default options + */ +exports.default = { + /** + * Custom class to be added to the `.colorpicker-element` element + * + * @type {String|null} + * @default null + */ + customClass: null, + /** + * Sets a initial color, ignoring the one from the element/input value or the data-color attribute. + * + * @type {(String|ColorItem|boolean)} + * @default false + */ + color: false, + /** + * Fallback color to use when the given color is invalid. + * If false, the latest valid color will be used as a fallback. + * + * @type {String|ColorItem|boolean} + * @default false + */ + fallbackColor: false, + /** + * Forces an specific color format. If 'auto', it will be automatically detected the first time only, + * but if null it will be always recalculated. + * + * Note that the ending 'a' of the format meaning "alpha" has currently no effect, meaning that rgb is the same as + * rgba excepting if the alpha channel is disabled (see useAlpha). + * + * @type {('rgb'|'hex'|'hsl'|'auto'|null)} + * @default 'auto' + */ + format: 'auto', + /** + * Horizontal mode layout. + * + * If true, the hue and alpha channel bars will be rendered horizontally, above the saturation selector. + * + * @type {boolean} + * @default false + */ + horizontal: false, + /** + * Forces to show the colorpicker as an inline element. + * + * Note that if there is no container specified, the inline element + * will be added to the body, so you may want to set the container option. + * + * @type {boolean} + * @default false + */ + inline: false, + /** + * Container where the colorpicker is appended to in the DOM. + * + * If is a string (CSS selector), the colorpicker will be placed inside this container. + * If true, the `.colorpicker-element` element itself will be used as the container. + * If false, the document body is used as the container, unless it is a popover (in this case it is appended to the + * popover body instead). + * + * @type {String|boolean} + * @default false + */ + container: false, + /** + * Bootstrap Popover options. + * The trigger, content and html options are always ignored. + * + * @type {boolean} + * @default Object + */ + popover: { + animation: true, + placement: 'bottom', + fallbackPlacement: 'flip' + }, + /** + * If true, loads the 'debugger' extension automatically, which logs the events in the console + * @type {boolean} + * @default false + */ + debug: false, + /** + * Child CSS selector for the colorpicker input. + * + * @type {String} + * @default 'input' + */ + input: 'input', + /** + * Child CSS selector for the colorpicker addon. + * If it exists, the child element background will be changed on color change. + * + * @type {String} + * @default '.colorpicker-trigger, .colorpicker-input-addon' + */ + addon: '.colorpicker-input-addon', + /** + * If true, the input content will be replaced always with a valid color, + * if false, the invalid color will be left in the input, + * while the internal color object will still resolve into a valid one. + * + * @type {boolean} + * @default true + */ + autoInputFallback: true, + /** + * If true a hash will be prepended to hexadecimal colors. + * If false, the hash will be removed. + * This only affects the input values in hexadecimal format. + * + * @type {boolean} + * @default true + */ + useHashPrefix: true, + /** + * If true, the alpha channel bar will be displayed no matter what. + * + * If false, it will be always hidden and alpha channel will be disabled also programmatically, meaning that + * the selected or typed color will be always opaque. + * + * If null, the alpha channel will be automatically disabled/enabled depending if the initial color format supports + * alpha or not. + * + * @type {boolean} + * @default true + */ + useAlpha: true, + /** + * Colorpicker widget template + * @type {String} + * @example + * + *
+ *
+ *
+ *
+ *
+ * + *
+ *
+ */ + template: '
\n
\n
\n
\n
\n \n
\n
', + /** + * + * Associative object with the extension class name and its config. + * Colorpicker comes with many bundled extensions: debugger, palette, preview and swatches (a superset of palette). + * + * @type {Object[]} + * @example + * extensions: [ + * { + * name: 'swatches' + * options: { + * colors: { + * 'primary': '#337ab7', + * 'success': '#5cb85c', + * 'info': '#5bc0de', + * 'warning': '#f0ad4e', + * 'danger': '#d9534f' + * }, + * namesAsValues: true + * } + * } + * ] + */ + extensions: [{ + name: 'preview', + options: { + showText: true + } + }], + /** + * Vertical sliders configuration + * @type {Object} + */ + sliders: { + saturation: { + selector: '.colorpicker-saturation', + maxLeft: sliderSize, + maxTop: sliderSize, + callLeft: 'setSaturationRatio', + callTop: 'setValueRatio' + }, + hue: { + selector: '.colorpicker-hue', + maxLeft: 0, + maxTop: sliderSize, + callLeft: false, + callTop: 'setHueRatio' + }, + alpha: { + selector: '.colorpicker-alpha', + childSelector: '.colorpicker-alpha-color', + maxLeft: 0, + maxTop: sliderSize, + callLeft: false, + callTop: 'setAlphaRatio' + } + }, + /** + * Horizontal sliders configuration + * @type {Object} + */ + slidersHorz: { + saturation: { + selector: '.colorpicker-saturation', + maxLeft: sliderSize, + maxTop: sliderSize, + callLeft: 'setSaturationRatio', + callTop: 'setValueRatio' + }, + hue: { + selector: '.colorpicker-hue', + maxLeft: sliderSize, + maxTop: 0, + callLeft: 'setHueRatio', + callTop: false + }, + alpha: { + selector: '.colorpicker-alpha', + childSelector: '.colorpicker-alpha-color', + maxLeft: sliderSize, + maxTop: 0, + callLeft: 'setAlphaRatio', + callTop: false + } + } +}; +module.exports = exports.default; + +/***/ }), +/* 4 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; + +var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); + +var _Extension2 = __webpack_require__(1); + +var _Extension3 = _interopRequireDefault(_Extension2); + +var _jquery = __webpack_require__(0); + +var _jquery2 = _interopRequireDefault(_jquery); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + +function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } + +function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } + +var defaults = { + /** + * Key-value pairs defining a color alias and its CSS color representation. + * + * They can also be just an array of values. In that case, no special names are used, only the real colors. + * + * @type {Object|Array} + * @default null + * @example + * { + * 'black': '#000000', + * 'white': '#ffffff', + * 'red': '#FF0000', + * 'default': '#777777', + * 'primary': '#337ab7', + * 'success': '#5cb85c', + * 'info': '#5bc0de', + * 'warning': '#f0ad4e', + * 'danger': '#d9534f' + * } + * + * @example ['#f0ad4e', '#337ab7', '#5cb85c'] + */ + colors: null, + /** + * If true, when a color swatch is selected the name (alias) will be used as input value, + * otherwise the swatch real color value will be used. + * + * @type {boolean} + * @default true + */ + namesAsValues: true +}; + +/** + * Palette extension + * @ignore + */ + +var Palette = function (_Extension) { + _inherits(Palette, _Extension); + + _createClass(Palette, [{ + key: 'colors', + + + /** + * @returns {Object|Array} + */ + get: function get() { + return this.options.colors; + } + }]); + + function Palette(colorpicker) { + var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; + + _classCallCheck(this, Palette); + + var _this = _possibleConstructorReturn(this, (Palette.__proto__ || Object.getPrototypeOf(Palette)).call(this, colorpicker, _jquery2.default.extend(true, {}, defaults, options))); + + if (!Array.isArray(_this.options.colors) && _typeof(_this.options.colors) !== 'object') { + _this.options.colors = null; + } + return _this; + } + + /** + * @returns {int} + */ + + + _createClass(Palette, [{ + key: 'getLength', + value: function getLength() { + if (!this.options.colors) { + return 0; + } + + if (Array.isArray(this.options.colors)) { + return this.options.colors.length; + } + + if (_typeof(this.options.colors) === 'object') { + return Object.keys(this.options.colors).length; + } + + return 0; + } + }, { + key: 'resolveColor', + value: function resolveColor(color) { + var realColor = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true; + + if (this.getLength() <= 0) { + return false; + } + + // Array of colors + if (Array.isArray(this.options.colors)) { + if (this.options.colors.indexOf(color) >= 0) { + return color; + } + if (this.options.colors.indexOf(color.toUpperCase()) >= 0) { + return color.toUpperCase(); + } + if (this.options.colors.indexOf(color.toLowerCase()) >= 0) { + return color.toLowerCase(); + } + return false; + } + + if (_typeof(this.options.colors) !== 'object') { + return false; + } + + // Map of objects + if (!this.options.namesAsValues || realColor) { + return this.getValue(color, false); + } + return this.getName(color, this.getName('#' + color)); + } + + /** + * Given a color value, returns the corresponding color name or defaultValue. + * + * @param {String} value + * @param {*} defaultValue + * @returns {*} + */ + + }, { + key: 'getName', + value: function getName(value) { + var defaultValue = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false; + + if (!(typeof value === 'string') || !this.options.colors) { + return defaultValue; + } + for (var name in this.options.colors) { + if (!this.options.colors.hasOwnProperty(name)) { + continue; + } + if (this.options.colors[name].toLowerCase() === value.toLowerCase()) { + return name; + } + } + return defaultValue; + } + + /** + * Given a color name, returns the corresponding color value or defaultValue. + * + * @param {String} name + * @param {*} defaultValue + * @returns {*} + */ + + }, { + key: 'getValue', + value: function getValue(name) { + var defaultValue = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false; + + if (!(typeof name === 'string') || !this.options.colors) { + return defaultValue; + } + if (this.options.colors.hasOwnProperty(name)) { + return this.options.colors[name]; + } + return defaultValue; + } + }]); + + return Palette; +}(_Extension3.default); + +exports.default = Palette; +module.exports = exports.default; + +/***/ }), +/* 5 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +module.exports = { + "aliceblue": [240, 248, 255], + "antiquewhite": [250, 235, 215], + "aqua": [0, 255, 255], + "aquamarine": [127, 255, 212], + "azure": [240, 255, 255], + "beige": [245, 245, 220], + "bisque": [255, 228, 196], + "black": [0, 0, 0], + "blanchedalmond": [255, 235, 205], + "blue": [0, 0, 255], + "blueviolet": [138, 43, 226], + "brown": [165, 42, 42], + "burlywood": [222, 184, 135], + "cadetblue": [95, 158, 160], + "chartreuse": [127, 255, 0], + "chocolate": [210, 105, 30], + "coral": [255, 127, 80], + "cornflowerblue": [100, 149, 237], + "cornsilk": [255, 248, 220], + "crimson": [220, 20, 60], + "cyan": [0, 255, 255], + "darkblue": [0, 0, 139], + "darkcyan": [0, 139, 139], + "darkgoldenrod": [184, 134, 11], + "darkgray": [169, 169, 169], + "darkgreen": [0, 100, 0], + "darkgrey": [169, 169, 169], + "darkkhaki": [189, 183, 107], + "darkmagenta": [139, 0, 139], + "darkolivegreen": [85, 107, 47], + "darkorange": [255, 140, 0], + "darkorchid": [153, 50, 204], + "darkred": [139, 0, 0], + "darksalmon": [233, 150, 122], + "darkseagreen": [143, 188, 143], + "darkslateblue": [72, 61, 139], + "darkslategray": [47, 79, 79], + "darkslategrey": [47, 79, 79], + "darkturquoise": [0, 206, 209], + "darkviolet": [148, 0, 211], + "deeppink": [255, 20, 147], + "deepskyblue": [0, 191, 255], + "dimgray": [105, 105, 105], + "dimgrey": [105, 105, 105], + "dodgerblue": [30, 144, 255], + "firebrick": [178, 34, 34], + "floralwhite": [255, 250, 240], + "forestgreen": [34, 139, 34], + "fuchsia": [255, 0, 255], + "gainsboro": [220, 220, 220], + "ghostwhite": [248, 248, 255], + "gold": [255, 215, 0], + "goldenrod": [218, 165, 32], + "gray": [128, 128, 128], + "green": [0, 128, 0], + "greenyellow": [173, 255, 47], + "grey": [128, 128, 128], + "honeydew": [240, 255, 240], + "hotpink": [255, 105, 180], + "indianred": [205, 92, 92], + "indigo": [75, 0, 130], + "ivory": [255, 255, 240], + "khaki": [240, 230, 140], + "lavender": [230, 230, 250], + "lavenderblush": [255, 240, 245], + "lawngreen": [124, 252, 0], + "lemonchiffon": [255, 250, 205], + "lightblue": [173, 216, 230], + "lightcoral": [240, 128, 128], + "lightcyan": [224, 255, 255], + "lightgoldenrodyellow": [250, 250, 210], + "lightgray": [211, 211, 211], + "lightgreen": [144, 238, 144], + "lightgrey": [211, 211, 211], + "lightpink": [255, 182, 193], + "lightsalmon": [255, 160, 122], + "lightseagreen": [32, 178, 170], + "lightskyblue": [135, 206, 250], + "lightslategray": [119, 136, 153], + "lightslategrey": [119, 136, 153], + "lightsteelblue": [176, 196, 222], + "lightyellow": [255, 255, 224], + "lime": [0, 255, 0], + "limegreen": [50, 205, 50], + "linen": [250, 240, 230], + "magenta": [255, 0, 255], + "maroon": [128, 0, 0], + "mediumaquamarine": [102, 205, 170], + "mediumblue": [0, 0, 205], + "mediumorchid": [186, 85, 211], + "mediumpurple": [147, 112, 219], + "mediumseagreen": [60, 179, 113], + "mediumslateblue": [123, 104, 238], + "mediumspringgreen": [0, 250, 154], + "mediumturquoise": [72, 209, 204], + "mediumvioletred": [199, 21, 133], + "midnightblue": [25, 25, 112], + "mintcream": [245, 255, 250], + "mistyrose": [255, 228, 225], + "moccasin": [255, 228, 181], + "navajowhite": [255, 222, 173], + "navy": [0, 0, 128], + "oldlace": [253, 245, 230], + "olive": [128, 128, 0], + "olivedrab": [107, 142, 35], + "orange": [255, 165, 0], + "orangered": [255, 69, 0], + "orchid": [218, 112, 214], + "palegoldenrod": [238, 232, 170], + "palegreen": [152, 251, 152], + "paleturquoise": [175, 238, 238], + "palevioletred": [219, 112, 147], + "papayawhip": [255, 239, 213], + "peachpuff": [255, 218, 185], + "peru": [205, 133, 63], + "pink": [255, 192, 203], + "plum": [221, 160, 221], + "powderblue": [176, 224, 230], + "purple": [128, 0, 128], + "rebeccapurple": [102, 51, 153], + "red": [255, 0, 0], + "rosybrown": [188, 143, 143], + "royalblue": [65, 105, 225], + "saddlebrown": [139, 69, 19], + "salmon": [250, 128, 114], + "sandybrown": [244, 164, 96], + "seagreen": [46, 139, 87], + "seashell": [255, 245, 238], + "sienna": [160, 82, 45], + "silver": [192, 192, 192], + "skyblue": [135, 206, 235], + "slateblue": [106, 90, 205], + "slategray": [112, 128, 144], + "slategrey": [112, 128, 144], + "snow": [255, 250, 250], + "springgreen": [0, 255, 127], + "steelblue": [70, 130, 180], + "tan": [210, 180, 140], + "teal": [0, 128, 128], + "thistle": [216, 191, 216], + "tomato": [255, 99, 71], + "turquoise": [64, 224, 208], + "violet": [238, 130, 238], + "wheat": [245, 222, 179], + "white": [255, 255, 255], + "whitesmoke": [245, 245, 245], + "yellow": [255, 255, 0], + "yellowgreen": [154, 205, 50] +}; + + +/***/ }), +/* 6 */ +/***/ (function(module, exports, __webpack_require__) { + +/* MIT license */ +var cssKeywords = __webpack_require__(5); + +// NOTE: conversions should only return primitive values (i.e. arrays, or +// values that give correct `typeof` results). +// do not use box values types (i.e. Number(), String(), etc.) + +var reverseKeywords = {}; +for (var key in cssKeywords) { + if (cssKeywords.hasOwnProperty(key)) { + reverseKeywords[cssKeywords[key]] = key; + } +} + +var convert = module.exports = { + rgb: {channels: 3, labels: 'rgb'}, + hsl: {channels: 3, labels: 'hsl'}, + hsv: {channels: 3, labels: 'hsv'}, + hwb: {channels: 3, labels: 'hwb'}, + cmyk: {channels: 4, labels: 'cmyk'}, + xyz: {channels: 3, labels: 'xyz'}, + lab: {channels: 3, labels: 'lab'}, + lch: {channels: 3, labels: 'lch'}, + hex: {channels: 1, labels: ['hex']}, + keyword: {channels: 1, labels: ['keyword']}, + ansi16: {channels: 1, labels: ['ansi16']}, + ansi256: {channels: 1, labels: ['ansi256']}, + hcg: {channels: 3, labels: ['h', 'c', 'g']}, + apple: {channels: 3, labels: ['r16', 'g16', 'b16']}, + gray: {channels: 1, labels: ['gray']} +}; + +// hide .channels and .labels properties +for (var model in convert) { + if (convert.hasOwnProperty(model)) { + if (!('channels' in convert[model])) { + throw new Error('missing channels property: ' + model); + } + + if (!('labels' in convert[model])) { + throw new Error('missing channel labels property: ' + model); + } + + if (convert[model].labels.length !== convert[model].channels) { + throw new Error('channel and label counts mismatch: ' + model); + } + + var channels = convert[model].channels; + var labels = convert[model].labels; + delete convert[model].channels; + delete convert[model].labels; + Object.defineProperty(convert[model], 'channels', {value: channels}); + Object.defineProperty(convert[model], 'labels', {value: labels}); + } +} + +convert.rgb.hsl = function (rgb) { + var r = rgb[0] / 255; + var g = rgb[1] / 255; + var b = rgb[2] / 255; + var min = Math.min(r, g, b); + var max = Math.max(r, g, b); + var delta = max - min; + var h; + var s; + var l; + + if (max === min) { + h = 0; + } else if (r === max) { + h = (g - b) / delta; + } else if (g === max) { + h = 2 + (b - r) / delta; + } else if (b === max) { + h = 4 + (r - g) / delta; + } + + h = Math.min(h * 60, 360); + + if (h < 0) { + h += 360; + } + + l = (min + max) / 2; + + if (max === min) { + s = 0; + } else if (l <= 0.5) { + s = delta / (max + min); + } else { + s = delta / (2 - max - min); + } + + return [h, s * 100, l * 100]; +}; + +convert.rgb.hsv = function (rgb) { + var rdif; + var gdif; + var bdif; + var h; + var s; + + var r = rgb[0] / 255; + var g = rgb[1] / 255; + var b = rgb[2] / 255; + var v = Math.max(r, g, b); + var diff = v - Math.min(r, g, b); + var diffc = function (c) { + return (v - c) / 6 / diff + 1 / 2; + }; + + if (diff === 0) { + h = s = 0; + } else { + s = diff / v; + rdif = diffc(r); + gdif = diffc(g); + bdif = diffc(b); + + if (r === v) { + h = bdif - gdif; + } else if (g === v) { + h = (1 / 3) + rdif - bdif; + } else if (b === v) { + h = (2 / 3) + gdif - rdif; + } + if (h < 0) { + h += 1; + } else if (h > 1) { + h -= 1; + } + } + + return [ + h * 360, + s * 100, + v * 100 + ]; +}; + +convert.rgb.hwb = function (rgb) { + var r = rgb[0]; + var g = rgb[1]; + var b = rgb[2]; + var h = convert.rgb.hsl(rgb)[0]; + var w = 1 / 255 * Math.min(r, Math.min(g, b)); + + b = 1 - 1 / 255 * Math.max(r, Math.max(g, b)); + + return [h, w * 100, b * 100]; +}; + +convert.rgb.cmyk = function (rgb) { + var r = rgb[0] / 255; + var g = rgb[1] / 255; + var b = rgb[2] / 255; + var c; + var m; + var y; + var k; + + k = Math.min(1 - r, 1 - g, 1 - b); + c = (1 - r - k) / (1 - k) || 0; + m = (1 - g - k) / (1 - k) || 0; + y = (1 - b - k) / (1 - k) || 0; + + return [c * 100, m * 100, y * 100, k * 100]; +}; + +/** + * See https://en.m.wikipedia.org/wiki/Euclidean_distance#Squared_Euclidean_distance + * */ +function comparativeDistance(x, y) { + return ( + Math.pow(x[0] - y[0], 2) + + Math.pow(x[1] - y[1], 2) + + Math.pow(x[2] - y[2], 2) + ); +} + +convert.rgb.keyword = function (rgb) { + var reversed = reverseKeywords[rgb]; + if (reversed) { + return reversed; + } + + var currentClosestDistance = Infinity; + var currentClosestKeyword; + + for (var keyword in cssKeywords) { + if (cssKeywords.hasOwnProperty(keyword)) { + var value = cssKeywords[keyword]; + + // Compute comparative distance + var distance = comparativeDistance(rgb, value); + + // Check if its less, if so set as closest + if (distance < currentClosestDistance) { + currentClosestDistance = distance; + currentClosestKeyword = keyword; + } + } + } + + return currentClosestKeyword; +}; + +convert.keyword.rgb = function (keyword) { + return cssKeywords[keyword]; +}; + +convert.rgb.xyz = function (rgb) { + var r = rgb[0] / 255; + var g = rgb[1] / 255; + var b = rgb[2] / 255; + + // assume sRGB + r = r > 0.04045 ? Math.pow(((r + 0.055) / 1.055), 2.4) : (r / 12.92); + g = g > 0.04045 ? Math.pow(((g + 0.055) / 1.055), 2.4) : (g / 12.92); + b = b > 0.04045 ? Math.pow(((b + 0.055) / 1.055), 2.4) : (b / 12.92); + + var x = (r * 0.4124) + (g * 0.3576) + (b * 0.1805); + var y = (r * 0.2126) + (g * 0.7152) + (b * 0.0722); + var z = (r * 0.0193) + (g * 0.1192) + (b * 0.9505); + + return [x * 100, y * 100, z * 100]; +}; + +convert.rgb.lab = function (rgb) { + var xyz = convert.rgb.xyz(rgb); + var x = xyz[0]; + var y = xyz[1]; + var z = xyz[2]; + var l; + var a; + var b; + + x /= 95.047; + y /= 100; + z /= 108.883; + + x = x > 0.008856 ? Math.pow(x, 1 / 3) : (7.787 * x) + (16 / 116); + y = y > 0.008856 ? Math.pow(y, 1 / 3) : (7.787 * y) + (16 / 116); + z = z > 0.008856 ? Math.pow(z, 1 / 3) : (7.787 * z) + (16 / 116); + + l = (116 * y) - 16; + a = 500 * (x - y); + b = 200 * (y - z); + + return [l, a, b]; +}; + +convert.hsl.rgb = function (hsl) { + var h = hsl[0] / 360; + var s = hsl[1] / 100; + var l = hsl[2] / 100; + var t1; + var t2; + var t3; + var rgb; + var val; + + if (s === 0) { + val = l * 255; + return [val, val, val]; + } + + if (l < 0.5) { + t2 = l * (1 + s); + } else { + t2 = l + s - l * s; + } + + t1 = 2 * l - t2; + + rgb = [0, 0, 0]; + for (var i = 0; i < 3; i++) { + t3 = h + 1 / 3 * -(i - 1); + if (t3 < 0) { + t3++; + } + if (t3 > 1) { + t3--; + } + + if (6 * t3 < 1) { + val = t1 + (t2 - t1) * 6 * t3; + } else if (2 * t3 < 1) { + val = t2; + } else if (3 * t3 < 2) { + val = t1 + (t2 - t1) * (2 / 3 - t3) * 6; + } else { + val = t1; + } + + rgb[i] = val * 255; + } + + return rgb; +}; + +convert.hsl.hsv = function (hsl) { + var h = hsl[0]; + var s = hsl[1] / 100; + var l = hsl[2] / 100; + var smin = s; + var lmin = Math.max(l, 0.01); + var sv; + var v; + + l *= 2; + s *= (l <= 1) ? l : 2 - l; + smin *= lmin <= 1 ? lmin : 2 - lmin; + v = (l + s) / 2; + sv = l === 0 ? (2 * smin) / (lmin + smin) : (2 * s) / (l + s); + + return [h, sv * 100, v * 100]; +}; + +convert.hsv.rgb = function (hsv) { + var h = hsv[0] / 60; + var s = hsv[1] / 100; + var v = hsv[2] / 100; + var hi = Math.floor(h) % 6; + + var f = h - Math.floor(h); + var p = 255 * v * (1 - s); + var q = 255 * v * (1 - (s * f)); + var t = 255 * v * (1 - (s * (1 - f))); + v *= 255; + + switch (hi) { + case 0: + return [v, t, p]; + case 1: + return [q, v, p]; + case 2: + return [p, v, t]; + case 3: + return [p, q, v]; + case 4: + return [t, p, v]; + case 5: + return [v, p, q]; + } +}; + +convert.hsv.hsl = function (hsv) { + var h = hsv[0]; + var s = hsv[1] / 100; + var v = hsv[2] / 100; + var vmin = Math.max(v, 0.01); + var lmin; + var sl; + var l; + + l = (2 - s) * v; + lmin = (2 - s) * vmin; + sl = s * vmin; + sl /= (lmin <= 1) ? lmin : 2 - lmin; + sl = sl || 0; + l /= 2; + + return [h, sl * 100, l * 100]; +}; + +// http://dev.w3.org/csswg/css-color/#hwb-to-rgb +convert.hwb.rgb = function (hwb) { + var h = hwb[0] / 360; + var wh = hwb[1] / 100; + var bl = hwb[2] / 100; + var ratio = wh + bl; + var i; + var v; + var f; + var n; + + // wh + bl cant be > 1 + if (ratio > 1) { + wh /= ratio; + bl /= ratio; + } + + i = Math.floor(6 * h); + v = 1 - bl; + f = 6 * h - i; + + if ((i & 0x01) !== 0) { + f = 1 - f; + } + + n = wh + f * (v - wh); // linear interpolation + + var r; + var g; + var b; + switch (i) { + default: + case 6: + case 0: r = v; g = n; b = wh; break; + case 1: r = n; g = v; b = wh; break; + case 2: r = wh; g = v; b = n; break; + case 3: r = wh; g = n; b = v; break; + case 4: r = n; g = wh; b = v; break; + case 5: r = v; g = wh; b = n; break; + } + + return [r * 255, g * 255, b * 255]; +}; + +convert.cmyk.rgb = function (cmyk) { + var c = cmyk[0] / 100; + var m = cmyk[1] / 100; + var y = cmyk[2] / 100; + var k = cmyk[3] / 100; + var r; + var g; + var b; + + r = 1 - Math.min(1, c * (1 - k) + k); + g = 1 - Math.min(1, m * (1 - k) + k); + b = 1 - Math.min(1, y * (1 - k) + k); + + return [r * 255, g * 255, b * 255]; +}; + +convert.xyz.rgb = function (xyz) { + var x = xyz[0] / 100; + var y = xyz[1] / 100; + var z = xyz[2] / 100; + var r; + var g; + var b; + + r = (x * 3.2406) + (y * -1.5372) + (z * -0.4986); + g = (x * -0.9689) + (y * 1.8758) + (z * 0.0415); + b = (x * 0.0557) + (y * -0.2040) + (z * 1.0570); + + // assume sRGB + r = r > 0.0031308 + ? ((1.055 * Math.pow(r, 1.0 / 2.4)) - 0.055) + : r * 12.92; + + g = g > 0.0031308 + ? ((1.055 * Math.pow(g, 1.0 / 2.4)) - 0.055) + : g * 12.92; + + b = b > 0.0031308 + ? ((1.055 * Math.pow(b, 1.0 / 2.4)) - 0.055) + : b * 12.92; + + r = Math.min(Math.max(0, r), 1); + g = Math.min(Math.max(0, g), 1); + b = Math.min(Math.max(0, b), 1); + + return [r * 255, g * 255, b * 255]; +}; + +convert.xyz.lab = function (xyz) { + var x = xyz[0]; + var y = xyz[1]; + var z = xyz[2]; + var l; + var a; + var b; + + x /= 95.047; + y /= 100; + z /= 108.883; + + x = x > 0.008856 ? Math.pow(x, 1 / 3) : (7.787 * x) + (16 / 116); + y = y > 0.008856 ? Math.pow(y, 1 / 3) : (7.787 * y) + (16 / 116); + z = z > 0.008856 ? Math.pow(z, 1 / 3) : (7.787 * z) + (16 / 116); + + l = (116 * y) - 16; + a = 500 * (x - y); + b = 200 * (y - z); + + return [l, a, b]; +}; + +convert.lab.xyz = function (lab) { + var l = lab[0]; + var a = lab[1]; + var b = lab[2]; + var x; + var y; + var z; + + y = (l + 16) / 116; + x = a / 500 + y; + z = y - b / 200; + + var y2 = Math.pow(y, 3); + var x2 = Math.pow(x, 3); + var z2 = Math.pow(z, 3); + y = y2 > 0.008856 ? y2 : (y - 16 / 116) / 7.787; + x = x2 > 0.008856 ? x2 : (x - 16 / 116) / 7.787; + z = z2 > 0.008856 ? z2 : (z - 16 / 116) / 7.787; + + x *= 95.047; + y *= 100; + z *= 108.883; + + return [x, y, z]; +}; + +convert.lab.lch = function (lab) { + var l = lab[0]; + var a = lab[1]; + var b = lab[2]; + var hr; + var h; + var c; + + hr = Math.atan2(b, a); + h = hr * 360 / 2 / Math.PI; + + if (h < 0) { + h += 360; + } + + c = Math.sqrt(a * a + b * b); + + return [l, c, h]; +}; + +convert.lch.lab = function (lch) { + var l = lch[0]; + var c = lch[1]; + var h = lch[2]; + var a; + var b; + var hr; + + hr = h / 360 * 2 * Math.PI; + a = c * Math.cos(hr); + b = c * Math.sin(hr); + + return [l, a, b]; +}; + +convert.rgb.ansi16 = function (args) { + var r = args[0]; + var g = args[1]; + var b = args[2]; + var value = 1 in arguments ? arguments[1] : convert.rgb.hsv(args)[2]; // hsv -> ansi16 optimization + + value = Math.round(value / 50); + + if (value === 0) { + return 30; + } + + var ansi = 30 + + ((Math.round(b / 255) << 2) + | (Math.round(g / 255) << 1) + | Math.round(r / 255)); + + if (value === 2) { + ansi += 60; + } + + return ansi; +}; + +convert.hsv.ansi16 = function (args) { + // optimization here; we already know the value and don't need to get + // it converted for us. + return convert.rgb.ansi16(convert.hsv.rgb(args), args[2]); +}; + +convert.rgb.ansi256 = function (args) { + var r = args[0]; + var g = args[1]; + var b = args[2]; + + // we use the extended greyscale palette here, with the exception of + // black and white. normal palette only has 4 greyscale shades. + if (r === g && g === b) { + if (r < 8) { + return 16; + } + + if (r > 248) { + return 231; + } + + return Math.round(((r - 8) / 247) * 24) + 232; + } + + var ansi = 16 + + (36 * Math.round(r / 255 * 5)) + + (6 * Math.round(g / 255 * 5)) + + Math.round(b / 255 * 5); + + return ansi; +}; + +convert.ansi16.rgb = function (args) { + var color = args % 10; + + // handle greyscale + if (color === 0 || color === 7) { + if (args > 50) { + color += 3.5; + } + + color = color / 10.5 * 255; + + return [color, color, color]; + } + + var mult = (~~(args > 50) + 1) * 0.5; + var r = ((color & 1) * mult) * 255; + var g = (((color >> 1) & 1) * mult) * 255; + var b = (((color >> 2) & 1) * mult) * 255; + + return [r, g, b]; +}; + +convert.ansi256.rgb = function (args) { + // handle greyscale + if (args >= 232) { + var c = (args - 232) * 10 + 8; + return [c, c, c]; + } + + args -= 16; + + var rem; + var r = Math.floor(args / 36) / 5 * 255; + var g = Math.floor((rem = args % 36) / 6) / 5 * 255; + var b = (rem % 6) / 5 * 255; + + return [r, g, b]; +}; + +convert.rgb.hex = function (args) { + var integer = ((Math.round(args[0]) & 0xFF) << 16) + + ((Math.round(args[1]) & 0xFF) << 8) + + (Math.round(args[2]) & 0xFF); + + var string = integer.toString(16).toUpperCase(); + return '000000'.substring(string.length) + string; +}; + +convert.hex.rgb = function (args) { + var match = args.toString(16).match(/[a-f0-9]{6}|[a-f0-9]{3}/i); + if (!match) { + return [0, 0, 0]; + } + + var colorString = match[0]; + + if (match[0].length === 3) { + colorString = colorString.split('').map(function (char) { + return char + char; + }).join(''); + } + + var integer = parseInt(colorString, 16); + var r = (integer >> 16) & 0xFF; + var g = (integer >> 8) & 0xFF; + var b = integer & 0xFF; + + return [r, g, b]; +}; + +convert.rgb.hcg = function (rgb) { + var r = rgb[0] / 255; + var g = rgb[1] / 255; + var b = rgb[2] / 255; + var max = Math.max(Math.max(r, g), b); + var min = Math.min(Math.min(r, g), b); + var chroma = (max - min); + var grayscale; + var hue; + + if (chroma < 1) { + grayscale = min / (1 - chroma); + } else { + grayscale = 0; + } + + if (chroma <= 0) { + hue = 0; + } else + if (max === r) { + hue = ((g - b) / chroma) % 6; + } else + if (max === g) { + hue = 2 + (b - r) / chroma; + } else { + hue = 4 + (r - g) / chroma + 4; + } + + hue /= 6; + hue %= 1; + + return [hue * 360, chroma * 100, grayscale * 100]; +}; + +convert.hsl.hcg = function (hsl) { + var s = hsl[1] / 100; + var l = hsl[2] / 100; + var c = 1; + var f = 0; + + if (l < 0.5) { + c = 2.0 * s * l; + } else { + c = 2.0 * s * (1.0 - l); + } + + if (c < 1.0) { + f = (l - 0.5 * c) / (1.0 - c); + } + + return [hsl[0], c * 100, f * 100]; +}; + +convert.hsv.hcg = function (hsv) { + var s = hsv[1] / 100; + var v = hsv[2] / 100; + + var c = s * v; + var f = 0; + + if (c < 1.0) { + f = (v - c) / (1 - c); + } + + return [hsv[0], c * 100, f * 100]; +}; + +convert.hcg.rgb = function (hcg) { + var h = hcg[0] / 360; + var c = hcg[1] / 100; + var g = hcg[2] / 100; + + if (c === 0.0) { + return [g * 255, g * 255, g * 255]; + } + + var pure = [0, 0, 0]; + var hi = (h % 1) * 6; + var v = hi % 1; + var w = 1 - v; + var mg = 0; + + switch (Math.floor(hi)) { + case 0: + pure[0] = 1; pure[1] = v; pure[2] = 0; break; + case 1: + pure[0] = w; pure[1] = 1; pure[2] = 0; break; + case 2: + pure[0] = 0; pure[1] = 1; pure[2] = v; break; + case 3: + pure[0] = 0; pure[1] = w; pure[2] = 1; break; + case 4: + pure[0] = v; pure[1] = 0; pure[2] = 1; break; + default: + pure[0] = 1; pure[1] = 0; pure[2] = w; + } + + mg = (1.0 - c) * g; + + return [ + (c * pure[0] + mg) * 255, + (c * pure[1] + mg) * 255, + (c * pure[2] + mg) * 255 + ]; +}; + +convert.hcg.hsv = function (hcg) { + var c = hcg[1] / 100; + var g = hcg[2] / 100; + + var v = c + g * (1.0 - c); + var f = 0; + + if (v > 0.0) { + f = c / v; + } + + return [hcg[0], f * 100, v * 100]; +}; + +convert.hcg.hsl = function (hcg) { + var c = hcg[1] / 100; + var g = hcg[2] / 100; + + var l = g * (1.0 - c) + 0.5 * c; + var s = 0; + + if (l > 0.0 && l < 0.5) { + s = c / (2 * l); + } else + if (l >= 0.5 && l < 1.0) { + s = c / (2 * (1 - l)); + } + + return [hcg[0], s * 100, l * 100]; +}; + +convert.hcg.hwb = function (hcg) { + var c = hcg[1] / 100; + var g = hcg[2] / 100; + var v = c + g * (1.0 - c); + return [hcg[0], (v - c) * 100, (1 - v) * 100]; +}; + +convert.hwb.hcg = function (hwb) { + var w = hwb[1] / 100; + var b = hwb[2] / 100; + var v = 1 - b; + var c = v - w; + var g = 0; + + if (c < 1) { + g = (v - c) / (1 - c); + } + + return [hwb[0], c * 100, g * 100]; +}; + +convert.apple.rgb = function (apple) { + return [(apple[0] / 65535) * 255, (apple[1] / 65535) * 255, (apple[2] / 65535) * 255]; +}; + +convert.rgb.apple = function (rgb) { + return [(rgb[0] / 255) * 65535, (rgb[1] / 255) * 65535, (rgb[2] / 255) * 65535]; +}; + +convert.gray.rgb = function (args) { + return [args[0] / 100 * 255, args[0] / 100 * 255, args[0] / 100 * 255]; +}; + +convert.gray.hsl = convert.gray.hsv = function (args) { + return [0, 0, args[0]]; +}; + +convert.gray.hwb = function (gray) { + return [0, 100, gray[0]]; +}; + +convert.gray.cmyk = function (gray) { + return [0, 0, 0, gray[0]]; +}; + +convert.gray.lab = function (gray) { + return [gray[0], 0, 0]; +}; + +convert.gray.hex = function (gray) { + var val = Math.round(gray[0] / 100 * 255) & 0xFF; + var integer = (val << 16) + (val << 8) + val; + + var string = integer.toString(16).toUpperCase(); + return '000000'.substring(string.length) + string; +}; + +convert.rgb.gray = function (rgb) { + var val = (rgb[0] + rgb[1] + rgb[2]) / 3; + return [val / 255 * 100]; +}; + + +/***/ }), +/* 7 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; + +var _Colorpicker = __webpack_require__(8); + +var _Colorpicker2 = _interopRequireDefault(_Colorpicker); + +var _jquery = __webpack_require__(0); + +var _jquery2 = _interopRequireDefault(_jquery); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +var plugin = 'colorpicker'; + +_jquery2.default[plugin] = _Colorpicker2.default; + +// Colorpicker jQuery Plugin API +_jquery2.default.fn[plugin] = function (option) { + var fnArgs = Array.prototype.slice.call(arguments, 1), + isSingleElement = this.length === 1, + returnValue = null; + + var $elements = this.each(function () { + var $this = (0, _jquery2.default)(this), + inst = $this.data(plugin), + options = (typeof option === 'undefined' ? 'undefined' : _typeof(option)) === 'object' ? option : {}; + + // Create instance if does not exist + if (!inst) { + inst = new _Colorpicker2.default(this, options); + $this.data(plugin, inst); + } + + if (!isSingleElement) { + return; + } + + returnValue = $this; + + if (typeof option === 'string') { + if (option === 'colorpicker') { + // Return colorpicker instance: e.g. .colorpicker('colorpicker') + returnValue = inst; + } else if (_jquery2.default.isFunction(inst[option])) { + // Return method call return value: e.g. .colorpicker('isEnabled') + returnValue = inst[option].apply(inst, fnArgs); + } else { + // Return property value: e.g. .colorpicker('element') + returnValue = inst[option]; + } + } + }); + + return isSingleElement ? returnValue : $elements; +}; + +_jquery2.default.fn[plugin].constructor = _Colorpicker2.default; + +/***/ }), +/* 8 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); + +var _Extension = __webpack_require__(1); + +var _Extension2 = _interopRequireDefault(_Extension); + +var _options = __webpack_require__(3); + +var _options2 = _interopRequireDefault(_options); + +var _extensions = __webpack_require__(9); + +var _extensions2 = _interopRequireDefault(_extensions); + +var _jquery = __webpack_require__(0); + +var _jquery2 = _interopRequireDefault(_jquery); + +var _SliderHandler = __webpack_require__(13); + +var _SliderHandler2 = _interopRequireDefault(_SliderHandler); + +var _PopupHandler = __webpack_require__(14); + +var _PopupHandler2 = _interopRequireDefault(_PopupHandler); + +var _InputHandler = __webpack_require__(15); + +var _InputHandler2 = _interopRequireDefault(_InputHandler); + +var _ColorHandler = __webpack_require__(22); + +var _ColorHandler2 = _interopRequireDefault(_ColorHandler); + +var _PickerHandler = __webpack_require__(23); + +var _PickerHandler2 = _interopRequireDefault(_PickerHandler); + +var _AddonHandler = __webpack_require__(24); + +var _AddonHandler2 = _interopRequireDefault(_AddonHandler); + +var _ColorItem = __webpack_require__(2); + +var _ColorItem2 = _interopRequireDefault(_ColorItem); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + +var colorPickerIdCounter = 0; + +var root = typeof self !== 'undefined' ? self : undefined; // window + +/** + * Colorpicker widget class + */ + +var Colorpicker = function () { + _createClass(Colorpicker, [{ + key: 'color', + + + /** + * Internal color object + * + * @type {Color|null} + */ + get: function get() { + return this.colorHandler.color; + } + + /** + * Internal color format + * + * @type {String|null} + */ + + }, { + key: 'format', + get: function get() { + return this.colorHandler.format; + } + + /** + * Getter of the picker element + * + * @returns {jQuery|HTMLElement} + */ + + }, { + key: 'picker', + get: function get() { + return this.pickerHandler.picker; + } + + /** + * @fires Colorpicker#colorpickerCreate + * @param {Object|String} element + * @param {Object} options + * @constructor + */ + + }], [{ + key: 'Color', + + /** + * Color class + * + * @static + * @type {Color} + */ + get: function get() { + return _ColorItem2.default; + } + + /** + * Extension class + * + * @static + * @type {Extension} + */ + + }, { + key: 'Extension', + get: function get() { + return _Extension2.default; + } + }]); + + function Colorpicker(element, options) { + _classCallCheck(this, Colorpicker); + + colorPickerIdCounter += 1; + /** + * The colorpicker instance number + * @type {number} + */ + this.id = colorPickerIdCounter; + + /** + * Latest colorpicker event + * + * @type {{name: String, e: *}} + */ + this.lastEvent = { + alias: null, + e: null + }; + + /** + * The element that the colorpicker is bound to + * + * @type {*|jQuery} + */ + this.element = (0, _jquery2.default)(element).addClass('colorpicker-element').attr('data-colorpicker-id', this.id); + + /** + * @type {defaults} + */ + this.options = _jquery2.default.extend(true, {}, _options2.default, options, this.element.data()); + + /** + * @type {boolean} + * @private + */ + this.disabled = false; + + /** + * Extensions added to this instance + * + * @type {Extension[]} + */ + this.extensions = []; + + /** + * The element where the + * @type {*|jQuery} + */ + this.container = this.options.container === true || this.options.container !== true && this.options.inline === true ? this.element : this.options.container; + + this.container = this.container !== false ? (0, _jquery2.default)(this.container) : false; + + /** + * @type {InputHandler} + */ + this.inputHandler = new _InputHandler2.default(this); + /** + * @type {ColorHandler} + */ + this.colorHandler = new _ColorHandler2.default(this); + /** + * @type {SliderHandler} + */ + this.sliderHandler = new _SliderHandler2.default(this); + /** + * @type {PopupHandler} + */ + this.popupHandler = new _PopupHandler2.default(this, root); + /** + * @type {PickerHandler} + */ + this.pickerHandler = new _PickerHandler2.default(this); + /** + * @type {AddonHandler} + */ + this.addonHandler = new _AddonHandler2.default(this); + + this.init(); + + // Emit a create event + (0, _jquery2.default)(_jquery2.default.proxy(function () { + /** + * (Colorpicker) When the Colorpicker instance has been created and the DOM is ready. + * + * @event Colorpicker#colorpickerCreate + */ + this.trigger('colorpickerCreate'); + }, this)); + } + + /** + * Initializes the plugin + * @private + */ + + + _createClass(Colorpicker, [{ + key: 'init', + value: function init() { + // Init addon + this.addonHandler.bind(); + + // Init input + this.inputHandler.bind(); + + // Init extensions (before initializing the color) + this.initExtensions(); + + // Init color + this.colorHandler.bind(); + + // Init picker + this.pickerHandler.bind(); + + // Init sliders and popup + this.sliderHandler.bind(); + this.popupHandler.bind(); + + // Inject into the DOM (this may make it visible) + this.pickerHandler.attach(); + + // Update all components + this.update(); + + if (this.inputHandler.isDisabled()) { + this.disable(); + } + } + + /** + * Initializes the plugin extensions + * @private + */ + + }, { + key: 'initExtensions', + value: function initExtensions() { + var _this = this; + + if (!Array.isArray(this.options.extensions)) { + this.options.extensions = []; + } + + if (this.options.debug) { + this.options.extensions.push({ name: 'debugger' }); + } + + // Register and instantiate extensions + this.options.extensions.forEach(function (ext) { + _this.registerExtension(Colorpicker.extensions[ext.name.toLowerCase()], ext.options || {}); + }); + } + + /** + * Creates and registers the given extension + * + * @param {Extension} ExtensionClass The extension class to instantiate + * @param {Object} [config] Extension configuration + * @returns {Extension} + */ + + }, { + key: 'registerExtension', + value: function registerExtension(ExtensionClass) { + var config = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; + + var ext = new ExtensionClass(this, config); + + this.extensions.push(ext); + return ext; + } + + /** + * Destroys the current instance + * + * @fires Colorpicker#colorpickerDestroy + */ + + }, { + key: 'destroy', + value: function destroy() { + var color = this.color; + + this.sliderHandler.unbind(); + this.inputHandler.unbind(); + this.popupHandler.unbind(); + this.colorHandler.unbind(); + this.addonHandler.unbind(); + this.pickerHandler.unbind(); + + this.element.removeClass('colorpicker-element').removeData('colorpicker', 'color').off('.colorpicker'); + + /** + * (Colorpicker) When the instance is destroyed with all events unbound. + * + * @event Colorpicker#colorpickerDestroy + */ + this.trigger('colorpickerDestroy', color); + } + + /** + * Shows the colorpicker widget if hidden. + * If the colorpicker is disabled this call will be ignored. + * + * @fires Colorpicker#colorpickerShow + * @param {Event} [e] + */ + + }, { + key: 'show', + value: function show(e) { + this.popupHandler.show(e); + } + + /** + * Hides the colorpicker widget. + * + * @fires Colorpicker#colorpickerHide + * @param {Event} [e] + */ + + }, { + key: 'hide', + value: function hide(e) { + this.popupHandler.hide(e); + } + + /** + * Toggles the colorpicker between visible and hidden. + * + * @fires Colorpicker#colorpickerShow + * @fires Colorpicker#colorpickerHide + * @param {Event} [e] + */ + + }, { + key: 'toggle', + value: function toggle(e) { + this.popupHandler.toggle(e); + } + + /** + * Returns the current color value as string + * + * @param {String|*} [defaultValue] + * @returns {String|*} + */ + + }, { + key: 'getValue', + value: function getValue() { + var defaultValue = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : null; + + var val = this.colorHandler.color; + + val = val instanceof _ColorItem2.default ? val : defaultValue; + + if (val instanceof _ColorItem2.default) { + return val.string(this.format); + } + + return val; + } + + /** + * Sets the color manually + * + * @fires Colorpicker#colorpickerChange + * @param {String|Color} val + */ + + }, { + key: 'setValue', + value: function setValue(val) { + if (this.isDisabled()) { + return; + } + var ch = this.colorHandler; + + if (ch.hasColor() && !!val && ch.color.equals(val) || !ch.hasColor() && !val) { + // same color or still empty + return; + } + + ch.color = val ? ch.createColor(val, this.options.autoInputFallback) : null; + + /** + * (Colorpicker) When the color is set programmatically with setValue(). + * + * @event Colorpicker#colorpickerChange + */ + this.trigger('colorpickerChange', ch.color, val); + + // force update if color has changed to empty + this.update(); + } + + /** + * Updates the UI and the input color according to the internal color. + * + * @fires Colorpicker#colorpickerUpdate + */ + + }, { + key: 'update', + value: function update() { + if (this.colorHandler.hasColor()) { + this.inputHandler.update(); + } else { + this.colorHandler.assureColor(); + } + + this.addonHandler.update(); + this.pickerHandler.update(); + + /** + * (Colorpicker) Fired when the widget is updated. + * + * @event Colorpicker#colorpickerUpdate + */ + this.trigger('colorpickerUpdate'); + } + + /** + * Enables the widget and the input if any + * + * @fires Colorpicker#colorpickerEnable + * @returns {boolean} + */ + + }, { + key: 'enable', + value: function enable() { + this.inputHandler.enable(); + this.disabled = false; + this.picker.removeClass('colorpicker-disabled'); + + /** + * (Colorpicker) When the widget has been enabled. + * + * @event Colorpicker#colorpickerEnable + */ + this.trigger('colorpickerEnable'); + return true; + } + + /** + * Disables the widget and the input if any + * + * @fires Colorpicker#colorpickerDisable + * @returns {boolean} + */ + + }, { + key: 'disable', + value: function disable() { + this.inputHandler.disable(); + this.disabled = true; + this.picker.addClass('colorpicker-disabled'); + + /** + * (Colorpicker) When the widget has been disabled. + * + * @event Colorpicker#colorpickerDisable + */ + this.trigger('colorpickerDisable'); + return true; + } + + /** + * Returns true if this instance is enabled + * @returns {boolean} + */ + + }, { + key: 'isEnabled', + value: function isEnabled() { + return !this.isDisabled(); + } + + /** + * Returns true if this instance is disabled + * @returns {boolean} + */ + + }, { + key: 'isDisabled', + value: function isDisabled() { + return this.disabled === true; + } + + /** + * Triggers a Colorpicker event. + * + * @param eventName + * @param color + * @param value + */ + + }, { + key: 'trigger', + value: function trigger(eventName) { + var color = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null; + var value = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : null; + + this.element.trigger({ + type: eventName, + colorpicker: this, + color: color ? color : this.color, + value: value ? value : this.getValue() + }); + } + }]); + + return Colorpicker; +}(); + +/** + * Colorpicker extension classes, indexed by extension name + * + * @static + * @type {Object} a map between the extension name and its class + */ + + +Colorpicker.extensions = _extensions2.default; + +exports.default = Colorpicker; +module.exports = exports.default; + +/***/ }), +/* 9 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.Palette = exports.Swatches = exports.Preview = exports.Debugger = undefined; + +var _Debugger = __webpack_require__(10); + +var _Debugger2 = _interopRequireDefault(_Debugger); + +var _Preview = __webpack_require__(11); + +var _Preview2 = _interopRequireDefault(_Preview); + +var _Swatches = __webpack_require__(12); + +var _Swatches2 = _interopRequireDefault(_Swatches); + +var _Palette = __webpack_require__(4); + +var _Palette2 = _interopRequireDefault(_Palette); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +exports.Debugger = _Debugger2.default; +exports.Preview = _Preview2.default; +exports.Swatches = _Swatches2.default; +exports.Palette = _Palette2.default; +exports.default = { + 'debugger': _Debugger2.default, + 'preview': _Preview2.default, + 'swatches': _Swatches2.default, + 'palette': _Palette2.default +}; + +/***/ }), +/* 10 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); + +var _get = function get(object, property, receiver) { if (object === null) object = Function.prototype; var desc = Object.getOwnPropertyDescriptor(object, property); if (desc === undefined) { var parent = Object.getPrototypeOf(object); if (parent === null) { return undefined; } else { return get(parent, property, receiver); } } else if ("value" in desc) { return desc.value; } else { var getter = desc.get; if (getter === undefined) { return undefined; } return getter.call(receiver); } }; + +var _Extension2 = __webpack_require__(1); + +var _Extension3 = _interopRequireDefault(_Extension2); + +var _jquery = __webpack_require__(0); + +var _jquery2 = _interopRequireDefault(_jquery); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + +function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } + +function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } + +/** + * Debugger extension class + * @alias DebuggerExtension + * @ignore + */ +var Debugger = function (_Extension) { + _inherits(Debugger, _Extension); + + function Debugger(colorpicker) { + var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; + + _classCallCheck(this, Debugger); + + /** + * @type {number} + */ + var _this = _possibleConstructorReturn(this, (Debugger.__proto__ || Object.getPrototypeOf(Debugger)).call(this, colorpicker, options)); + + _this.eventCounter = 0; + if (_this.colorpicker.inputHandler.hasInput()) { + _this.colorpicker.inputHandler.input.on('change.colorpicker-ext', _jquery2.default.proxy(_this.onChangeInput, _this)); + } + return _this; + } + + /** + * @fires DebuggerExtension#colorpickerDebug + * @param {string} eventName + * @param {*} args + */ + + + _createClass(Debugger, [{ + key: 'log', + value: function log(eventName) { + var _console; + + for (var _len = arguments.length, args = Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) { + args[_key - 1] = arguments[_key]; + } + + this.eventCounter += 1; + + var logMessage = '#' + this.eventCounter + ': Colorpicker#' + this.colorpicker.id + ' [' + eventName + ']'; + + (_console = console).debug.apply(_console, [logMessage].concat(args)); + + /** + * Whenever the debugger logs an event, this other event is emitted. + * + * @event DebuggerExtension#colorpickerDebug + * @type {object} The event object + * @property {Colorpicker} colorpicker The Colorpicker instance + * @property {ColorItem} color The color instance + * @property {{debugger: DebuggerExtension, eventName: String, logArgs: Array, logMessage: String}} debug + * The debug info + */ + this.colorpicker.element.trigger({ + type: 'colorpickerDebug', + colorpicker: this.colorpicker, + color: this.color, + value: null, + debug: { + debugger: this, + eventName: eventName, + logArgs: args, + logMessage: logMessage + } + }); + } + }, { + key: 'resolveColor', + value: function resolveColor(color) { + var realColor = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true; + + this.log('resolveColor()', color, realColor); + return false; + } + }, { + key: 'onCreate', + value: function onCreate(event) { + this.log('colorpickerCreate'); + return _get(Debugger.prototype.__proto__ || Object.getPrototypeOf(Debugger.prototype), 'onCreate', this).call(this, event); + } + }, { + key: 'onDestroy', + value: function onDestroy(event) { + this.log('colorpickerDestroy'); + this.eventCounter = 0; + + if (this.colorpicker.inputHandler.hasInput()) { + this.colorpicker.inputHandler.input.off('.colorpicker-ext'); + } + + return _get(Debugger.prototype.__proto__ || Object.getPrototypeOf(Debugger.prototype), 'onDestroy', this).call(this, event); + } + }, { + key: 'onUpdate', + value: function onUpdate(event) { + this.log('colorpickerUpdate'); + } + + /** + * @listens Colorpicker#change + * @param {Event} event + */ + + }, { + key: 'onChangeInput', + value: function onChangeInput(event) { + this.log('input:change.colorpicker', event.value, event.color); + } + }, { + key: 'onChange', + value: function onChange(event) { + this.log('colorpickerChange', event.value, event.color); + } + }, { + key: 'onInvalid', + value: function onInvalid(event) { + this.log('colorpickerInvalid', event.value, event.color); + } + }, { + key: 'onHide', + value: function onHide(event) { + this.log('colorpickerHide'); + this.eventCounter = 0; + } + }, { + key: 'onShow', + value: function onShow(event) { + this.log('colorpickerShow'); + } + }, { + key: 'onDisable', + value: function onDisable(event) { + this.log('colorpickerDisable'); + } + }, { + key: 'onEnable', + value: function onEnable(event) { + this.log('colorpickerEnable'); + } + }]); + + return Debugger; +}(_Extension3.default); + +exports.default = Debugger; +module.exports = exports.default; + +/***/ }), +/* 11 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); + +var _get = function get(object, property, receiver) { if (object === null) object = Function.prototype; var desc = Object.getOwnPropertyDescriptor(object, property); if (desc === undefined) { var parent = Object.getPrototypeOf(object); if (parent === null) { return undefined; } else { return get(parent, property, receiver); } } else if ("value" in desc) { return desc.value; } else { var getter = desc.get; if (getter === undefined) { return undefined; } return getter.call(receiver); } }; + +var _Extension2 = __webpack_require__(1); + +var _Extension3 = _interopRequireDefault(_Extension2); + +var _jquery = __webpack_require__(0); + +var _jquery2 = _interopRequireDefault(_jquery); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + +function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } + +function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } + +/** + * Color preview extension + * @ignore + */ +var Preview = function (_Extension) { + _inherits(Preview, _Extension); + + function Preview(colorpicker) { + var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; + + _classCallCheck(this, Preview); + + var _this = _possibleConstructorReturn(this, (Preview.__proto__ || Object.getPrototypeOf(Preview)).call(this, colorpicker, _jquery2.default.extend(true, {}, { + template: '
', + showText: true, + format: colorpicker.format + }, options))); + + _this.element = (0, _jquery2.default)(_this.options.template); + _this.elementInner = _this.element.find('div'); + return _this; + } + + _createClass(Preview, [{ + key: 'onCreate', + value: function onCreate(event) { + _get(Preview.prototype.__proto__ || Object.getPrototypeOf(Preview.prototype), 'onCreate', this).call(this, event); + this.colorpicker.picker.append(this.element); + } + }, { + key: 'onUpdate', + value: function onUpdate(event) { + _get(Preview.prototype.__proto__ || Object.getPrototypeOf(Preview.prototype), 'onUpdate', this).call(this, event); + + if (!event.color) { + this.elementInner.css('backgroundColor', null).css('color', null).html(''); + return; + } + + this.elementInner.css('backgroundColor', event.color.toRgbString()); + + if (this.options.showText) { + this.elementInner.html(event.color.string(this.options.format || this.colorpicker.format)); + + if (event.color.isDark() && event.color.alpha > 0.5) { + this.elementInner.css('color', 'white'); + } else { + this.elementInner.css('color', 'black'); + } + } + } + }]); + + return Preview; +}(_Extension3.default); + +exports.default = Preview; +module.exports = exports.default; + +/***/ }), +/* 12 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); + +var _get = function get(object, property, receiver) { if (object === null) object = Function.prototype; var desc = Object.getOwnPropertyDescriptor(object, property); if (desc === undefined) { var parent = Object.getPrototypeOf(object); if (parent === null) { return undefined; } else { return get(parent, property, receiver); } } else if ("value" in desc) { return desc.value; } else { var getter = desc.get; if (getter === undefined) { return undefined; } return getter.call(receiver); } }; + +var _Palette2 = __webpack_require__(4); + +var _Palette3 = _interopRequireDefault(_Palette2); + +var _jquery = __webpack_require__(0); + +var _jquery2 = _interopRequireDefault(_jquery); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + +function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } + +function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } + +var defaults = { + barTemplate: '
\n
\n
', + swatchTemplate: '' +}; + +/** + * Color swatches extension + * @ignore + */ + +var Swatches = function (_Palette) { + _inherits(Swatches, _Palette); + + function Swatches(colorpicker) { + var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; + + _classCallCheck(this, Swatches); + + var _this = _possibleConstructorReturn(this, (Swatches.__proto__ || Object.getPrototypeOf(Swatches)).call(this, colorpicker, _jquery2.default.extend(true, {}, defaults, options))); + + _this.element = null; + return _this; + } + + _createClass(Swatches, [{ + key: 'isEnabled', + value: function isEnabled() { + return this.getLength() > 0; + } + }, { + key: 'onCreate', + value: function onCreate(event) { + _get(Swatches.prototype.__proto__ || Object.getPrototypeOf(Swatches.prototype), 'onCreate', this).call(this, event); + + if (!this.isEnabled()) { + return; + } + + this.element = (0, _jquery2.default)(this.options.barTemplate); + this.load(); + this.colorpicker.picker.append(this.element); + } + }, { + key: 'load', + value: function load() { + var _this2 = this; + + var colorpicker = this.colorpicker, + swatchContainer = this.element.find('.colorpicker-swatches--inner'), + isAliased = this.options.namesAsValues === true && !Array.isArray(this.colors); + + swatchContainer.empty(); + + _jquery2.default.each(this.colors, function (name, value) { + var $swatch = (0, _jquery2.default)(_this2.options.swatchTemplate).attr('data-name', name).attr('data-value', value).attr('title', isAliased ? name + ': ' + value : value).on('mousedown.colorpicker touchstart.colorpicker', function (e) { + var $sw = (0, _jquery2.default)(this); + + // e.preventDefault(); + + colorpicker.setValue(isAliased ? $sw.attr('data-name') : $sw.attr('data-value')); + }); + + $swatch.find('.colorpicker-swatch--inner').css('background-color', value); + + swatchContainer.append($swatch); + }); + + swatchContainer.append((0, _jquery2.default)('')); + } + }]); + + return Swatches; +}(_Palette3.default); + +exports.default = Swatches; +module.exports = exports.default; + +/***/ }), +/* 13 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); + +var _jquery = __webpack_require__(0); + +var _jquery2 = _interopRequireDefault(_jquery); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + +/** + * Class that handles all configured sliders on mouse or touch events. + * @ignore + */ +var SliderHandler = function () { + /** + * @param {Colorpicker} colorpicker + */ + function SliderHandler(colorpicker) { + _classCallCheck(this, SliderHandler); + + /** + * @type {Colorpicker} + */ + this.colorpicker = colorpicker; + /** + * @type {*|String} + * @private + */ + this.currentSlider = null; + /** + * @type {{left: number, top: number}} + * @private + */ + this.mousePointer = { + left: 0, + top: 0 + }; + + /** + * @type {Function} + */ + this.onMove = _jquery2.default.proxy(this.defaultOnMove, this); + } + + /** + * This function is called every time a slider guide is moved + * The scope of "this" is the SliderHandler object. + * + * @param {int} top + * @param {int} left + */ + + + _createClass(SliderHandler, [{ + key: 'defaultOnMove', + value: function defaultOnMove(top, left) { + if (!this.currentSlider) { + return; + } + + var slider = this.currentSlider, + cp = this.colorpicker, + ch = cp.colorHandler; + + // Create a color object + var color = !ch.hasColor() ? ch.getFallbackColor() : ch.color.getClone(); + + // Adjust the guide position + slider.guideStyle.left = left + 'px'; + slider.guideStyle.top = top + 'px'; + + // Adjust the color + if (slider.callLeft) { + color[slider.callLeft](left / slider.maxLeft); + } + if (slider.callTop) { + color[slider.callTop](top / slider.maxTop); + } + + // Set the new color + cp.setValue(color); + cp.popupHandler.focus(); + } + + /** + * Binds the colorpicker sliders to the mouse/touch events + */ + + }, { + key: 'bind', + value: function bind() { + var sliders = this.colorpicker.options.horizontal ? this.colorpicker.options.slidersHorz : this.colorpicker.options.sliders; + + var sliderClasses = []; + + for (var sliderName in sliders) { + if (!sliders.hasOwnProperty(sliderName)) { + continue; + } + + sliderClasses.push(sliders[sliderName].selector); + } + + this.colorpicker.picker.find(sliderClasses.join(', ')).on('mousedown.colorpicker touchstart.colorpicker', _jquery2.default.proxy(this.pressed, this)); + } + + /** + * Unbinds any event bound by this handler + */ + + }, { + key: 'unbind', + value: function unbind() { + (0, _jquery2.default)(this.colorpicker.picker).off({ + 'mousemove.colorpicker': _jquery2.default.proxy(this.moved, this), + 'touchmove.colorpicker': _jquery2.default.proxy(this.moved, this), + 'mouseup.colorpicker': _jquery2.default.proxy(this.released, this), + 'touchend.colorpicker': _jquery2.default.proxy(this.released, this) + }); + } + + /** + * Function triggered when clicking in one of the color adjustment bars + * + * @private + * @fires Colorpicker#mousemove + * @param {Event} e + */ + + }, { + key: 'pressed', + value: function pressed(e) { + if (this.colorpicker.isDisabled()) { + return; + } + this.colorpicker.lastEvent.alias = 'pressed'; + this.colorpicker.lastEvent.e = e; + + if (!e.pageX && !e.pageY && e.originalEvent && e.originalEvent.touches) { + e.pageX = e.originalEvent.touches[0].pageX; + e.pageY = e.originalEvent.touches[0].pageY; + } + // e.stopPropagation(); + // e.preventDefault(); + + var target = (0, _jquery2.default)(e.target); + + // detect the slider and set the limits and callbacks + var zone = target.closest('div'); + + var sliders = this.colorpicker.options.horizontal ? this.colorpicker.options.slidersHorz : this.colorpicker.options.sliders; + + if (zone.is('.colorpicker')) { + return; + } + + this.currentSlider = null; + + for (var sliderName in sliders) { + if (!sliders.hasOwnProperty(sliderName)) { + continue; + } + + var slider = sliders[sliderName]; + + if (zone.is(slider.selector)) { + this.currentSlider = _jquery2.default.extend({}, slider, { name: sliderName }); + break; + } else if (slider.childSelector !== undefined && zone.is(slider.childSelector)) { + this.currentSlider = _jquery2.default.extend({}, slider, { name: sliderName }); + zone = zone.parent(); // zone.parents(slider.selector).first() ? + break; + } + } + + var guide = zone.find('.colorpicker-guide').get(0); + + if (this.currentSlider === null || guide === null) { + return; + } + + var offset = zone.offset(); + + // reference to guide's style + this.currentSlider.guideStyle = guide.style; + this.currentSlider.left = e.pageX - offset.left; + this.currentSlider.top = e.pageY - offset.top; + this.mousePointer = { + left: e.pageX, + top: e.pageY + }; + + // TODO: fix moving outside the picker makes the guides to keep moving. The event needs to be bound to the window. + /** + * (window.document) Triggered on mousedown for the document object, + * so the color adjustment guide is moved to the clicked position. + * + * @event Colorpicker#mousemove + */ + (0, _jquery2.default)(this.colorpicker.picker).on({ + 'mousemove.colorpicker': _jquery2.default.proxy(this.moved, this), + 'touchmove.colorpicker': _jquery2.default.proxy(this.moved, this), + 'mouseup.colorpicker': _jquery2.default.proxy(this.released, this), + 'touchend.colorpicker': _jquery2.default.proxy(this.released, this) + }).trigger('mousemove'); + } + + /** + * Function triggered when dragging a guide inside one of the color adjustment bars. + * + * @private + * @param {Event} e + */ + + }, { + key: 'moved', + value: function moved(e) { + this.colorpicker.lastEvent.alias = 'moved'; + this.colorpicker.lastEvent.e = e; + + if (!e.pageX && !e.pageY && e.originalEvent && e.originalEvent.touches) { + e.pageX = e.originalEvent.touches[0].pageX; + e.pageY = e.originalEvent.touches[0].pageY; + } + + // e.stopPropagation(); + e.preventDefault(); // prevents scrolling on mobile + + var left = Math.max(0, Math.min(this.currentSlider.maxLeft, this.currentSlider.left + ((e.pageX || this.mousePointer.left) - this.mousePointer.left))); + + var top = Math.max(0, Math.min(this.currentSlider.maxTop, this.currentSlider.top + ((e.pageY || this.mousePointer.top) - this.mousePointer.top))); + + this.onMove(top, left); + } + + /** + * Function triggered when releasing the click in one of the color adjustment bars. + * + * @private + * @param {Event} e + */ + + }, { + key: 'released', + value: function released(e) { + this.colorpicker.lastEvent.alias = 'released'; + this.colorpicker.lastEvent.e = e; + + // e.stopPropagation(); + // e.preventDefault(); + + (0, _jquery2.default)(this.colorpicker.picker).off({ + 'mousemove.colorpicker': this.moved, + 'touchmove.colorpicker': this.moved, + 'mouseup.colorpicker': this.released, + 'touchend.colorpicker': this.released + }); + } + }]); + + return SliderHandler; +}(); + +exports.default = SliderHandler; +module.exports = exports.default; + +/***/ }), +/* 14 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); + +var _jquery = __webpack_require__(0); + +var _jquery2 = _interopRequireDefault(_jquery); + +var _options = __webpack_require__(3); + +var _options2 = _interopRequireDefault(_options); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + +/** + * Handles everything related to the UI of the colorpicker popup: show, hide, position,... + * @ignore + */ +var PopupHandler = function () { + /** + * @param {Colorpicker} colorpicker + * @param {Window} root + */ + function PopupHandler(colorpicker, root) { + _classCallCheck(this, PopupHandler); + + /** + * @type {Window} + */ + this.root = root; + /** + * @type {Colorpicker} + */ + this.colorpicker = colorpicker; + /** + * @type {jQuery} + */ + this.popoverTarget = null; + /** + * @type {jQuery} + */ + this.popoverTip = null; + + /** + * If true, the latest click was inside the popover + * @type {boolean} + */ + this.clicking = false; + /** + * @type {boolean} + */ + this.hidding = false; + /** + * @type {boolean} + */ + this.showing = false; + } + + /** + * @private + * @returns {jQuery|false} + */ + + + _createClass(PopupHandler, [{ + key: 'bind', + + + /** + * Binds the different colorpicker elements to the focus/mouse/touch events so it reacts in order to show or + * hide the colorpicker popup accordingly. It also adds the proper classes. + */ + value: function bind() { + var cp = this.colorpicker; + + if (cp.options.inline) { + cp.picker.addClass('colorpicker-inline colorpicker-visible'); + return; // no need to bind show/hide events for inline elements + } + + cp.picker.addClass('colorpicker-popup colorpicker-hidden'); + + // there is no input or addon + if (!this.hasInput && !this.hasAddon) { + return; + } + + // create Bootstrap 4 popover + if (cp.options.popover) { + this.createPopover(); + } + + // bind addon show/hide events + if (this.hasAddon) { + // enable focus on addons + if (!this.addon.attr('tabindex')) { + this.addon.attr('tabindex', 0); + } + + this.addon.on({ + 'mousedown.colorpicker touchstart.colorpicker': _jquery2.default.proxy(this.toggle, this) + }); + + this.addon.on({ + 'focus.colorpicker': _jquery2.default.proxy(this.show, this) + }); + + this.addon.on({ + 'focusout.colorpicker': _jquery2.default.proxy(this.hide, this) + }); + } + + // bind input show/hide events + if (this.hasInput && !this.hasAddon) { + this.input.on({ + 'mousedown.colorpicker touchstart.colorpicker': _jquery2.default.proxy(this.show, this), + 'focus.colorpicker': _jquery2.default.proxy(this.show, this) + }); + + this.input.on({ + 'focusout.colorpicker': _jquery2.default.proxy(this.hide, this) + }); + } + + // reposition popup on window resize + (0, _jquery2.default)(this.root).on('resize.colorpicker', _jquery2.default.proxy(this.reposition, this)); + } + + /** + * Unbinds any event bound by this handler + */ + + }, { + key: 'unbind', + value: function unbind() { + if (this.hasInput) { + this.input.off({ + 'mousedown.colorpicker touchstart.colorpicker': _jquery2.default.proxy(this.show, this), + 'focus.colorpicker': _jquery2.default.proxy(this.show, this) + }); + this.input.off({ + 'focusout.colorpicker': _jquery2.default.proxy(this.hide, this) + }); + } + + if (this.hasAddon) { + this.addon.off({ + 'mousedown.colorpicker touchstart.colorpicker': _jquery2.default.proxy(this.toggle, this) + }); + this.addon.off({ + 'focus.colorpicker': _jquery2.default.proxy(this.show, this) + }); + this.addon.off({ + 'focusout.colorpicker': _jquery2.default.proxy(this.hide, this) + }); + } + + if (this.popoverTarget) { + this.popoverTarget.popover('dispose'); + } + + (0, _jquery2.default)(this.root).off('resize.colorpicker', _jquery2.default.proxy(this.reposition, this)); + (0, _jquery2.default)(this.root.document).off('mousedown.colorpicker touchstart.colorpicker', _jquery2.default.proxy(this.hide, this)); + (0, _jquery2.default)(this.root.document).off('mousedown.colorpicker touchstart.colorpicker', _jquery2.default.proxy(this.onClickingInside, this)); + } + }, { + key: 'isClickingInside', + value: function isClickingInside(e) { + if (!e) { + return false; + } + + return this.isOrIsInside(this.popoverTip, e.currentTarget) || this.isOrIsInside(this.popoverTip, e.target) || this.isOrIsInside(this.colorpicker.picker, e.currentTarget) || this.isOrIsInside(this.colorpicker.picker, e.target); + } + }, { + key: 'isOrIsInside', + value: function isOrIsInside(container, element) { + if (!container || !element) { + return false; + } + + element = (0, _jquery2.default)(element); + + return element.is(container) || container.find(element).length > 0; + } + }, { + key: 'onClickingInside', + value: function onClickingInside(e) { + this.clicking = this.isClickingInside(e); + } + }, { + key: 'createPopover', + value: function createPopover() { + var cp = this.colorpicker; + + this.popoverTarget = this.hasAddon ? this.addon : this.input; + + cp.picker.addClass('colorpicker-bs-popover-content'); + + this.popoverTarget.popover(_jquery2.default.extend(true, {}, _options2.default.popover, cp.options.popover, { trigger: 'manual', content: cp.picker, html: true })); + + this.popoverTip = (0, _jquery2.default)(this.popoverTarget.popover('getTipElement').data('bs.popover').tip); + this.popoverTip.addClass('colorpicker-bs-popover'); + + this.popoverTarget.on('shown.bs.popover', _jquery2.default.proxy(this.fireShow, this)); + this.popoverTarget.on('hidden.bs.popover', _jquery2.default.proxy(this.fireHide, this)); + } + + /** + * If the widget is not inside a container or inline, rearranges its position relative to its element offset. + * + * @param {Event} [e] + * @private + */ + + }, { + key: 'reposition', + value: function reposition(e) { + if (this.popoverTarget && this.isVisible()) { + this.popoverTarget.popover('update'); + } + } + + /** + * Toggles the colorpicker between visible or hidden + * + * @fires Colorpicker#colorpickerShow + * @fires Colorpicker#colorpickerHide + * @param {Event} [e] + */ + + }, { + key: 'toggle', + value: function toggle(e) { + if (this.isVisible()) { + this.hide(e); + } else { + this.show(e); + } + } + + /** + * Shows the colorpicker widget if hidden. + * + * @fires Colorpicker#colorpickerShow + * @param {Event} [e] + */ + + }, { + key: 'show', + value: function show(e) { + if (this.isVisible() || this.showing || this.hidding) { + return; + } + + this.showing = true; + this.hidding = false; + this.clicking = false; + + var cp = this.colorpicker; + + cp.lastEvent.alias = 'show'; + cp.lastEvent.e = e; + + // Prevent showing browser native HTML5 colorpicker + if (e && (!this.hasInput || this.input.attr('type') === 'color') && e && e.preventDefault) { + e.stopPropagation(); + e.preventDefault(); + } + + // If it's a popover, add event to the document to hide the picker when clicking outside of it + if (this.isPopover) { + (0, _jquery2.default)(this.root).on('resize.colorpicker', _jquery2.default.proxy(this.reposition, this)); + } + + // add visible class before popover is shown + cp.picker.addClass('colorpicker-visible').removeClass('colorpicker-hidden'); + + if (this.popoverTarget) { + this.popoverTarget.popover('show'); + } else { + this.fireShow(); + } + } + }, { + key: 'fireShow', + value: function fireShow() { + this.hidding = false; + this.showing = false; + + if (this.isPopover) { + // Add event to hide on outside click + (0, _jquery2.default)(this.root.document).on('mousedown.colorpicker touchstart.colorpicker', _jquery2.default.proxy(this.hide, this)); + (0, _jquery2.default)(this.root.document).on('mousedown.colorpicker touchstart.colorpicker', _jquery2.default.proxy(this.onClickingInside, this)); + } + + /** + * (Colorpicker) When show() is called and the widget can be shown. + * + * @event Colorpicker#colorpickerShow + */ + this.colorpicker.trigger('colorpickerShow'); + } + + /** + * Hides the colorpicker widget. + * Hide is prevented when it is triggered by an event whose target element has been clicked/touched. + * + * @fires Colorpicker#colorpickerHide + * @param {Event} [e] + */ + + }, { + key: 'hide', + value: function hide(e) { + if (this.isHidden() || this.showing || this.hidding) { + return; + } + + var cp = this.colorpicker, + clicking = this.clicking || this.isClickingInside(e); + + this.hidding = true; + this.showing = false; + this.clicking = false; + + cp.lastEvent.alias = 'hide'; + cp.lastEvent.e = e; + + // TODO: fix having to click twice outside when losing focus and last 2 clicks where inside the colorpicker + + // Prevent hide if triggered by an event and an element inside the colorpicker has been clicked/touched + if (clicking) { + this.hidding = false; + return; + } + + if (this.popoverTarget) { + this.popoverTarget.popover('hide'); + } else { + this.fireHide(); + } + } + }, { + key: 'fireHide', + value: function fireHide() { + this.hidding = false; + this.showing = false; + + var cp = this.colorpicker; + + // add hidden class after popover is hidden + cp.picker.addClass('colorpicker-hidden').removeClass('colorpicker-visible'); + + // Unbind window and document events, since there is no need to keep them while the popup is hidden + (0, _jquery2.default)(this.root).off('resize.colorpicker', _jquery2.default.proxy(this.reposition, this)); + (0, _jquery2.default)(this.root.document).off('mousedown.colorpicker touchstart.colorpicker', _jquery2.default.proxy(this.hide, this)); + (0, _jquery2.default)(this.root.document).off('mousedown.colorpicker touchstart.colorpicker', _jquery2.default.proxy(this.onClickingInside, this)); + + /** + * (Colorpicker) When hide() is called and the widget can be hidden. + * + * @event Colorpicker#colorpickerHide + */ + cp.trigger('colorpickerHide'); + } + }, { + key: 'focus', + value: function focus() { + if (this.hasAddon) { + return this.addon.focus(); + } + if (this.hasInput) { + return this.input.focus(); + } + return false; + } + + /** + * Returns true if the colorpicker element has the colorpicker-visible class and not the colorpicker-hidden one. + * False otherwise. + * + * @returns {boolean} + */ + + }, { + key: 'isVisible', + value: function isVisible() { + return this.colorpicker.picker.hasClass('colorpicker-visible') && !this.colorpicker.picker.hasClass('colorpicker-hidden'); + } + + /** + * Returns true if the colorpicker element has the colorpicker-hidden class and not the colorpicker-visible one. + * False otherwise. + * + * @returns {boolean} + */ + + }, { + key: 'isHidden', + value: function isHidden() { + return this.colorpicker.picker.hasClass('colorpicker-hidden') && !this.colorpicker.picker.hasClass('colorpicker-visible'); + } + }, { + key: 'input', + get: function get() { + return this.colorpicker.inputHandler.input; + } + + /** + * @private + * @returns {boolean} + */ + + }, { + key: 'hasInput', + get: function get() { + return this.colorpicker.inputHandler.hasInput(); + } + + /** + * @private + * @returns {jQuery|false} + */ + + }, { + key: 'addon', + get: function get() { + return this.colorpicker.addonHandler.addon; + } + + /** + * @private + * @returns {boolean} + */ + + }, { + key: 'hasAddon', + get: function get() { + return this.colorpicker.addonHandler.hasAddon(); + } + + /** + * @private + * @returns {boolean} + */ + + }, { + key: 'isPopover', + get: function get() { + return !this.colorpicker.options.inline && !!this.popoverTip; + } + }]); + + return PopupHandler; +}(); + +exports.default = PopupHandler; +module.exports = exports.default; + +/***/ }), +/* 15 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); + +var _jquery = __webpack_require__(0); + +var _jquery2 = _interopRequireDefault(_jquery); + +var _ColorItem = __webpack_require__(2); + +var _ColorItem2 = _interopRequireDefault(_ColorItem); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + +/** + * Handles everything related to the colorpicker input + * @ignore + */ +var InputHandler = function () { + /** + * @param {Colorpicker} colorpicker + */ + function InputHandler(colorpicker) { + _classCallCheck(this, InputHandler); + + /** + * @type {Colorpicker} + */ + this.colorpicker = colorpicker; + /** + * @type {jQuery|false} + */ + this.input = this.colorpicker.element.is('input') ? this.colorpicker.element : this.colorpicker.options.input ? this.colorpicker.element.find(this.colorpicker.options.input) : false; + + if (this.input && this.input.length === 0) { + this.input = false; + } + + this._initValue(); + } + + _createClass(InputHandler, [{ + key: 'bind', + value: function bind() { + if (!this.hasInput()) { + return; + } + this.input.on({ + 'keyup.colorpicker': _jquery2.default.proxy(this.onkeyup, this) + }); + this.input.on({ + 'change.colorpicker': _jquery2.default.proxy(this.onchange, this) + }); + } + }, { + key: 'unbind', + value: function unbind() { + if (!this.hasInput()) { + return; + } + this.input.off('.colorpicker'); + } + }, { + key: '_initValue', + value: function _initValue() { + if (!this.hasInput()) { + return; + } + + var val = ''; + + [ + // candidates: + this.input.val(), this.input.data('color'), this.input.attr('data-color')].map(function (item) { + if (item && val === '') { + val = item; + } + }); + + if (val instanceof _ColorItem2.default) { + val = this.getFormattedColor(val.string(this.colorpicker.format)); + } else if (!(typeof val === 'string' || val instanceof String)) { + val = ''; + } + + this.input.prop('value', val); + } + + /** + * Returns the color string from the input value. + * If there is no input the return value is false. + * + * @returns {String|boolean} + */ + + }, { + key: 'getValue', + value: function getValue() { + if (!this.hasInput()) { + return false; + } + + return this.input.val(); + } + + /** + * If the input element is present, it updates the value with the current color object color string. + * If the value is changed, this method fires a "change" event on the input element. + * + * @param {String} val + * + * @fires Colorpicker#change + */ + + }, { + key: 'setValue', + value: function setValue(val) { + if (!this.hasInput()) { + return; + } + + var inputVal = this.input.prop('value'); + + val = val ? val : ''; + + if (val === (inputVal ? inputVal : '')) { + // No need to set value or trigger any event if nothing changed + return; + } + + this.input.prop('value', val); + + /** + * (Input) Triggered on the input element when a new color is selected. + * + * @event Colorpicker#change + */ + this.input.trigger({ + type: 'change', + colorpicker: this.colorpicker, + color: this.colorpicker.color, + value: val + }); + } + + /** + * Returns the formatted color string, with the formatting options applied + * (e.g. useHashPrefix) + * + * @param {String|null} val + * + * @returns {String} + */ + + }, { + key: 'getFormattedColor', + value: function getFormattedColor() { + var val = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : null; + + val = val ? val : this.colorpicker.colorHandler.getColorString(); + + if (!val) { + return ''; + } + + val = this.colorpicker.colorHandler.resolveColorDelegate(val, false); + + if (this.colorpicker.options.useHashPrefix === false) { + val = val.replace(/^#/g, ''); + } + + return val; + } + + /** + * Returns true if the widget has an associated input element, false otherwise + * @returns {boolean} + */ + + }, { + key: 'hasInput', + value: function hasInput() { + return this.input !== false; + } + + /** + * Returns true if the input exists and is disabled + * @returns {boolean} + */ + + }, { + key: 'isEnabled', + value: function isEnabled() { + return this.hasInput() && !this.isDisabled(); + } + + /** + * Returns true if the input exists and is disabled + * @returns {boolean} + */ + + }, { + key: 'isDisabled', + value: function isDisabled() { + return this.hasInput() && this.input.prop('disabled') === true; + } + + /** + * Disables the input if any + * + * @fires Colorpicker#colorpickerDisable + * @returns {boolean} + */ + + }, { + key: 'disable', + value: function disable() { + if (this.hasInput()) { + this.input.prop('disabled', true); + } + } + + /** + * Enables the input if any + * + * @fires Colorpicker#colorpickerEnable + * @returns {boolean} + */ + + }, { + key: 'enable', + value: function enable() { + if (this.hasInput()) { + this.input.prop('disabled', false); + } + } + + /** + * Calls setValue with the current internal color value + * + * @fires Colorpicker#change + */ + + }, { + key: 'update', + value: function update() { + if (!this.hasInput()) { + return; + } + + if (this.colorpicker.options.autoInputFallback === false && this.colorpicker.colorHandler.isInvalidColor()) { + // prevent update if color is invalid, autoInputFallback is disabled and the last event is keyup. + return; + } + + this.setValue(this.getFormattedColor()); + } + + /** + * Function triggered when the input has changed, so the colorpicker gets updated. + * + * @private + * @param {Event} e + * @returns {boolean} + */ + + }, { + key: 'onchange', + value: function onchange(e) { + this.colorpicker.lastEvent.alias = 'input.change'; + this.colorpicker.lastEvent.e = e; + + var val = this.getValue(); + + if (val !== e.value) { + this.colorpicker.setValue(val); + } + } + + /** + * Function triggered after a keyboard key has been released. + * + * @private + * @param {Event} e + * @returns {boolean} + */ + + }, { + key: 'onkeyup', + value: function onkeyup(e) { + this.colorpicker.lastEvent.alias = 'input.keyup'; + this.colorpicker.lastEvent.e = e; + + var val = this.getValue(); + + if (val !== e.value) { + this.colorpicker.setValue(val); + } + } + }]); + + return InputHandler; +}(); + +exports.default = InputHandler; +module.exports = exports.default; + +/***/ }), +/* 16 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +var colorString = __webpack_require__(17); +var convert = __webpack_require__(20); + +var _slice = [].slice; + +var skippedModels = [ + // to be honest, I don't really feel like keyword belongs in color convert, but eh. + 'keyword', + + // gray conflicts with some method names, and has its own method defined. + 'gray', + + // shouldn't really be in color-convert either... + 'hex' +]; + +var hashedModelKeys = {}; +Object.keys(convert).forEach(function (model) { + hashedModelKeys[_slice.call(convert[model].labels).sort().join('')] = model; +}); + +var limiters = {}; + +function Color(obj, model) { + if (!(this instanceof Color)) { + return new Color(obj, model); + } + + if (model && model in skippedModels) { + model = null; + } + + if (model && !(model in convert)) { + throw new Error('Unknown model: ' + model); + } + + var i; + var channels; + + if (obj == null) { // eslint-disable-line no-eq-null,eqeqeq + this.model = 'rgb'; + this.color = [0, 0, 0]; + this.valpha = 1; + } else if (obj instanceof Color) { + this.model = obj.model; + this.color = obj.color.slice(); + this.valpha = obj.valpha; + } else if (typeof obj === 'string') { + var result = colorString.get(obj); + if (result === null) { + throw new Error('Unable to parse color from string: ' + obj); + } + + this.model = result.model; + channels = convert[this.model].channels; + this.color = result.value.slice(0, channels); + this.valpha = typeof result.value[channels] === 'number' ? result.value[channels] : 1; + } else if (obj.length) { + this.model = model || 'rgb'; + channels = convert[this.model].channels; + var newArr = _slice.call(obj, 0, channels); + this.color = zeroArray(newArr, channels); + this.valpha = typeof obj[channels] === 'number' ? obj[channels] : 1; + } else if (typeof obj === 'number') { + // this is always RGB - can be converted later on. + obj &= 0xFFFFFF; + this.model = 'rgb'; + this.color = [ + (obj >> 16) & 0xFF, + (obj >> 8) & 0xFF, + obj & 0xFF + ]; + this.valpha = 1; + } else { + this.valpha = 1; + + var keys = Object.keys(obj); + if ('alpha' in obj) { + keys.splice(keys.indexOf('alpha'), 1); + this.valpha = typeof obj.alpha === 'number' ? obj.alpha : 0; + } + + var hashedKeys = keys.sort().join(''); + if (!(hashedKeys in hashedModelKeys)) { + throw new Error('Unable to parse color from object: ' + JSON.stringify(obj)); + } + + this.model = hashedModelKeys[hashedKeys]; + + var labels = convert[this.model].labels; + var color = []; + for (i = 0; i < labels.length; i++) { + color.push(obj[labels[i]]); + } + + this.color = zeroArray(color); + } + + // perform limitations (clamping, etc.) + if (limiters[this.model]) { + channels = convert[this.model].channels; + for (i = 0; i < channels; i++) { + var limit = limiters[this.model][i]; + if (limit) { + this.color[i] = limit(this.color[i]); + } + } + } + + this.valpha = Math.max(0, Math.min(1, this.valpha)); + + if (Object.freeze) { + Object.freeze(this); + } +} + +Color.prototype = { + toString: function () { + return this.string(); + }, + + toJSON: function () { + return this[this.model](); + }, + + string: function (places) { + var self = this.model in colorString.to ? this : this.rgb(); + self = self.round(typeof places === 'number' ? places : 1); + var args = self.valpha === 1 ? self.color : self.color.concat(this.valpha); + return colorString.to[self.model](args); + }, + + percentString: function (places) { + var self = this.rgb().round(typeof places === 'number' ? places : 1); + var args = self.valpha === 1 ? self.color : self.color.concat(this.valpha); + return colorString.to.rgb.percent(args); + }, + + array: function () { + return this.valpha === 1 ? this.color.slice() : this.color.concat(this.valpha); + }, + + object: function () { + var result = {}; + var channels = convert[this.model].channels; + var labels = convert[this.model].labels; + + for (var i = 0; i < channels; i++) { + result[labels[i]] = this.color[i]; + } + + if (this.valpha !== 1) { + result.alpha = this.valpha; + } + + return result; + }, + + unitArray: function () { + var rgb = this.rgb().color; + rgb[0] /= 255; + rgb[1] /= 255; + rgb[2] /= 255; + + if (this.valpha !== 1) { + rgb.push(this.valpha); + } + + return rgb; + }, + + unitObject: function () { + var rgb = this.rgb().object(); + rgb.r /= 255; + rgb.g /= 255; + rgb.b /= 255; + + if (this.valpha !== 1) { + rgb.alpha = this.valpha; + } + + return rgb; + }, + + round: function (places) { + places = Math.max(places || 0, 0); + return new Color(this.color.map(roundToPlace(places)).concat(this.valpha), this.model); + }, + + alpha: function (val) { + if (arguments.length) { + return new Color(this.color.concat(Math.max(0, Math.min(1, val))), this.model); + } + + return this.valpha; + }, + + // rgb + red: getset('rgb', 0, maxfn(255)), + green: getset('rgb', 1, maxfn(255)), + blue: getset('rgb', 2, maxfn(255)), + + hue: getset(['hsl', 'hsv', 'hsl', 'hwb', 'hcg'], 0, function (val) { return ((val % 360) + 360) % 360; }), // eslint-disable-line brace-style + + saturationl: getset('hsl', 1, maxfn(100)), + lightness: getset('hsl', 2, maxfn(100)), + + saturationv: getset('hsv', 1, maxfn(100)), + value: getset('hsv', 2, maxfn(100)), + + chroma: getset('hcg', 1, maxfn(100)), + gray: getset('hcg', 2, maxfn(100)), + + white: getset('hwb', 1, maxfn(100)), + wblack: getset('hwb', 2, maxfn(100)), + + cyan: getset('cmyk', 0, maxfn(100)), + magenta: getset('cmyk', 1, maxfn(100)), + yellow: getset('cmyk', 2, maxfn(100)), + black: getset('cmyk', 3, maxfn(100)), + + x: getset('xyz', 0, maxfn(100)), + y: getset('xyz', 1, maxfn(100)), + z: getset('xyz', 2, maxfn(100)), + + l: getset('lab', 0, maxfn(100)), + a: getset('lab', 1), + b: getset('lab', 2), + + keyword: function (val) { + if (arguments.length) { + return new Color(val); + } + + return convert[this.model].keyword(this.color); + }, + + hex: function (val) { + if (arguments.length) { + return new Color(val); + } + + return colorString.to.hex(this.rgb().round().color); + }, + + rgbNumber: function () { + var rgb = this.rgb().color; + return ((rgb[0] & 0xFF) << 16) | ((rgb[1] & 0xFF) << 8) | (rgb[2] & 0xFF); + }, + + luminosity: function () { + // http://www.w3.org/TR/WCAG20/#relativeluminancedef + var rgb = this.rgb().color; + + var lum = []; + for (var i = 0; i < rgb.length; i++) { + var chan = rgb[i] / 255; + lum[i] = (chan <= 0.03928) ? chan / 12.92 : Math.pow(((chan + 0.055) / 1.055), 2.4); + } + + return 0.2126 * lum[0] + 0.7152 * lum[1] + 0.0722 * lum[2]; + }, + + contrast: function (color2) { + // http://www.w3.org/TR/WCAG20/#contrast-ratiodef + var lum1 = this.luminosity(); + var lum2 = color2.luminosity(); + + if (lum1 > lum2) { + return (lum1 + 0.05) / (lum2 + 0.05); + } + + return (lum2 + 0.05) / (lum1 + 0.05); + }, + + level: function (color2) { + var contrastRatio = this.contrast(color2); + if (contrastRatio >= 7.1) { + return 'AAA'; + } + + return (contrastRatio >= 4.5) ? 'AA' : ''; + }, + + isDark: function () { + // YIQ equation from http://24ways.org/2010/calculating-color-contrast + var rgb = this.rgb().color; + var yiq = (rgb[0] * 299 + rgb[1] * 587 + rgb[2] * 114) / 1000; + return yiq < 128; + }, + + isLight: function () { + return !this.isDark(); + }, + + negate: function () { + var rgb = this.rgb(); + for (var i = 0; i < 3; i++) { + rgb.color[i] = 255 - rgb.color[i]; + } + return rgb; + }, + + lighten: function (ratio) { + var hsl = this.hsl(); + hsl.color[2] += hsl.color[2] * ratio; + return hsl; + }, + + darken: function (ratio) { + var hsl = this.hsl(); + hsl.color[2] -= hsl.color[2] * ratio; + return hsl; + }, + + saturate: function (ratio) { + var hsl = this.hsl(); + hsl.color[1] += hsl.color[1] * ratio; + return hsl; + }, + + desaturate: function (ratio) { + var hsl = this.hsl(); + hsl.color[1] -= hsl.color[1] * ratio; + return hsl; + }, + + whiten: function (ratio) { + var hwb = this.hwb(); + hwb.color[1] += hwb.color[1] * ratio; + return hwb; + }, + + blacken: function (ratio) { + var hwb = this.hwb(); + hwb.color[2] += hwb.color[2] * ratio; + return hwb; + }, + + grayscale: function () { + // http://en.wikipedia.org/wiki/Grayscale#Converting_color_to_grayscale + var rgb = this.rgb().color; + var val = rgb[0] * 0.3 + rgb[1] * 0.59 + rgb[2] * 0.11; + return Color.rgb(val, val, val); + }, + + fade: function (ratio) { + return this.alpha(this.valpha - (this.valpha * ratio)); + }, + + opaquer: function (ratio) { + return this.alpha(this.valpha + (this.valpha * ratio)); + }, + + rotate: function (degrees) { + var hsl = this.hsl(); + var hue = hsl.color[0]; + hue = (hue + degrees) % 360; + hue = hue < 0 ? 360 + hue : hue; + hsl.color[0] = hue; + return hsl; + }, + + mix: function (mixinColor, weight) { + // ported from sass implementation in C + // https://github.com/sass/libsass/blob/0e6b4a2850092356aa3ece07c6b249f0221caced/functions.cpp#L209 + if (!mixinColor || !mixinColor.rgb) { + throw new Error('Argument to "mix" was not a Color instance, but rather an instance of ' + typeof mixinColor); + } + var color1 = mixinColor.rgb(); + var color2 = this.rgb(); + var p = weight === undefined ? 0.5 : weight; + + var w = 2 * p - 1; + var a = color1.alpha() - color2.alpha(); + + var w1 = (((w * a === -1) ? w : (w + a) / (1 + w * a)) + 1) / 2.0; + var w2 = 1 - w1; + + return Color.rgb( + w1 * color1.red() + w2 * color2.red(), + w1 * color1.green() + w2 * color2.green(), + w1 * color1.blue() + w2 * color2.blue(), + color1.alpha() * p + color2.alpha() * (1 - p)); + } +}; + +// model conversion methods and static constructors +Object.keys(convert).forEach(function (model) { + if (skippedModels.indexOf(model) !== -1) { + return; + } + + var channels = convert[model].channels; + + // conversion methods + Color.prototype[model] = function () { + if (this.model === model) { + return new Color(this); + } + + if (arguments.length) { + return new Color(arguments, model); + } + + var newAlpha = typeof arguments[channels] === 'number' ? channels : this.valpha; + return new Color(assertArray(convert[this.model][model].raw(this.color)).concat(newAlpha), model); + }; + + // 'static' construction methods + Color[model] = function (color) { + if (typeof color === 'number') { + color = zeroArray(_slice.call(arguments), channels); + } + return new Color(color, model); + }; +}); + +function roundTo(num, places) { + return Number(num.toFixed(places)); +} + +function roundToPlace(places) { + return function (num) { + return roundTo(num, places); + }; +} + +function getset(model, channel, modifier) { + model = Array.isArray(model) ? model : [model]; + + model.forEach(function (m) { + (limiters[m] || (limiters[m] = []))[channel] = modifier; + }); + + model = model[0]; + + return function (val) { + var result; + + if (arguments.length) { + if (modifier) { + val = modifier(val); + } + + result = this[model](); + result.color[channel] = val; + return result; + } + + result = this[model]().color[channel]; + if (modifier) { + result = modifier(result); + } + + return result; + }; +} + +function maxfn(max) { + return function (v) { + return Math.max(0, Math.min(max, v)); + }; +} + +function assertArray(val) { + return Array.isArray(val) ? val : [val]; +} + +function zeroArray(arr, length) { + for (var i = 0; i < length; i++) { + if (typeof arr[i] !== 'number') { + arr[i] = 0; + } + } + + return arr; +} + +module.exports = Color; + + +/***/ }), +/* 17 */ +/***/ (function(module, exports, __webpack_require__) { + +/* MIT license */ +var colorNames = __webpack_require__(5); +var swizzle = __webpack_require__(18); + +var reverseNames = {}; + +// create a list of reverse color names +for (var name in colorNames) { + if (colorNames.hasOwnProperty(name)) { + reverseNames[colorNames[name]] = name; + } +} + +var cs = module.exports = { + to: {}, + get: {} +}; + +cs.get = function (string) { + var prefix = string.substring(0, 3).toLowerCase(); + var val; + var model; + switch (prefix) { + case 'hsl': + val = cs.get.hsl(string); + model = 'hsl'; + break; + case 'hwb': + val = cs.get.hwb(string); + model = 'hwb'; + break; + default: + val = cs.get.rgb(string); + model = 'rgb'; + break; + } + + if (!val) { + return null; + } + + return {model: model, value: val}; +}; + +cs.get.rgb = function (string) { + if (!string) { + return null; + } + + var abbr = /^#([a-f0-9]{3,4})$/i; + var hex = /^#([a-f0-9]{6})([a-f0-9]{2})?$/i; + var rgba = /^rgba?\(\s*([+-]?\d+)\s*,\s*([+-]?\d+)\s*,\s*([+-]?\d+)\s*(?:,\s*([+-]?[\d\.]+)\s*)?\)$/; + var per = /^rgba?\(\s*([+-]?[\d\.]+)\%\s*,\s*([+-]?[\d\.]+)\%\s*,\s*([+-]?[\d\.]+)\%\s*(?:,\s*([+-]?[\d\.]+)\s*)?\)$/; + var keyword = /(\D+)/; + + var rgb = [0, 0, 0, 1]; + var match; + var i; + var hexAlpha; + + if (match = string.match(hex)) { + hexAlpha = match[2]; + match = match[1]; + + for (i = 0; i < 3; i++) { + // https://jsperf.com/slice-vs-substr-vs-substring-methods-long-string/19 + var i2 = i * 2; + rgb[i] = parseInt(match.slice(i2, i2 + 2), 16); + } + + if (hexAlpha) { + rgb[3] = Math.round((parseInt(hexAlpha, 16) / 255) * 100) / 100; + } + } else if (match = string.match(abbr)) { + match = match[1]; + hexAlpha = match[3]; + + for (i = 0; i < 3; i++) { + rgb[i] = parseInt(match[i] + match[i], 16); + } + + if (hexAlpha) { + rgb[3] = Math.round((parseInt(hexAlpha + hexAlpha, 16) / 255) * 100) / 100; + } + } else if (match = string.match(rgba)) { + for (i = 0; i < 3; i++) { + rgb[i] = parseInt(match[i + 1], 0); + } + + if (match[4]) { + rgb[3] = parseFloat(match[4]); + } + } else if (match = string.match(per)) { + for (i = 0; i < 3; i++) { + rgb[i] = Math.round(parseFloat(match[i + 1]) * 2.55); + } + + if (match[4]) { + rgb[3] = parseFloat(match[4]); + } + } else if (match = string.match(keyword)) { + if (match[1] === 'transparent') { + return [0, 0, 0, 0]; + } + + rgb = colorNames[match[1]]; + + if (!rgb) { + return null; + } + + rgb[3] = 1; + + return rgb; + } else { + return null; + } + + for (i = 0; i < 3; i++) { + rgb[i] = clamp(rgb[i], 0, 255); + } + rgb[3] = clamp(rgb[3], 0, 1); + + return rgb; +}; + +cs.get.hsl = function (string) { + if (!string) { + return null; + } + + var hsl = /^hsla?\(\s*([+-]?(?:\d*\.)?\d+)(?:deg)?\s*,\s*([+-]?[\d\.]+)%\s*,\s*([+-]?[\d\.]+)%\s*(?:,\s*([+-]?[\d\.]+)\s*)?\)$/; + var match = string.match(hsl); + + if (match) { + var alpha = parseFloat(match[4]); + var h = (parseFloat(match[1]) + 360) % 360; + var s = clamp(parseFloat(match[2]), 0, 100); + var l = clamp(parseFloat(match[3]), 0, 100); + var a = clamp(isNaN(alpha) ? 1 : alpha, 0, 1); + + return [h, s, l, a]; + } + + return null; +}; + +cs.get.hwb = function (string) { + if (!string) { + return null; + } + + var hwb = /^hwb\(\s*([+-]?\d*[\.]?\d+)(?:deg)?\s*,\s*([+-]?[\d\.]+)%\s*,\s*([+-]?[\d\.]+)%\s*(?:,\s*([+-]?[\d\.]+)\s*)?\)$/; + var match = string.match(hwb); + + if (match) { + var alpha = parseFloat(match[4]); + var h = ((parseFloat(match[1]) % 360) + 360) % 360; + var w = clamp(parseFloat(match[2]), 0, 100); + var b = clamp(parseFloat(match[3]), 0, 100); + var a = clamp(isNaN(alpha) ? 1 : alpha, 0, 1); + return [h, w, b, a]; + } + + return null; +}; + +cs.to.hex = function () { + var rgba = swizzle(arguments); + + return ( + '#' + + hexDouble(rgba[0]) + + hexDouble(rgba[1]) + + hexDouble(rgba[2]) + + (rgba[3] < 1 + ? (hexDouble(Math.round(rgba[3] * 255))) + : '') + ); +}; + +cs.to.rgb = function () { + var rgba = swizzle(arguments); + + return rgba.length < 4 || rgba[3] === 1 + ? 'rgb(' + Math.round(rgba[0]) + ', ' + Math.round(rgba[1]) + ', ' + Math.round(rgba[2]) + ')' + : 'rgba(' + Math.round(rgba[0]) + ', ' + Math.round(rgba[1]) + ', ' + Math.round(rgba[2]) + ', ' + rgba[3] + ')'; +}; + +cs.to.rgb.percent = function () { + var rgba = swizzle(arguments); + + var r = Math.round(rgba[0] / 255 * 100); + var g = Math.round(rgba[1] / 255 * 100); + var b = Math.round(rgba[2] / 255 * 100); + + return rgba.length < 4 || rgba[3] === 1 + ? 'rgb(' + r + '%, ' + g + '%, ' + b + '%)' + : 'rgba(' + r + '%, ' + g + '%, ' + b + '%, ' + rgba[3] + ')'; +}; + +cs.to.hsl = function () { + var hsla = swizzle(arguments); + return hsla.length < 4 || hsla[3] === 1 + ? 'hsl(' + hsla[0] + ', ' + hsla[1] + '%, ' + hsla[2] + '%)' + : 'hsla(' + hsla[0] + ', ' + hsla[1] + '%, ' + hsla[2] + '%, ' + hsla[3] + ')'; +}; + +// hwb is a bit different than rgb(a) & hsl(a) since there is no alpha specific syntax +// (hwb have alpha optional & 1 is default value) +cs.to.hwb = function () { + var hwba = swizzle(arguments); + + var a = ''; + if (hwba.length >= 4 && hwba[3] !== 1) { + a = ', ' + hwba[3]; + } + + return 'hwb(' + hwba[0] + ', ' + hwba[1] + '%, ' + hwba[2] + '%' + a + ')'; +}; + +cs.to.keyword = function (rgb) { + return reverseNames[rgb.slice(0, 3)]; +}; + +// helpers +function clamp(num, min, max) { + return Math.min(Math.max(min, num), max); +} + +function hexDouble(num) { + var str = num.toString(16).toUpperCase(); + return (str.length < 2) ? '0' + str : str; +} + + +/***/ }), +/* 18 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +var isArrayish = __webpack_require__(19); + +var concat = Array.prototype.concat; +var slice = Array.prototype.slice; + +var swizzle = module.exports = function swizzle(args) { + var results = []; + + for (var i = 0, len = args.length; i < len; i++) { + var arg = args[i]; + + if (isArrayish(arg)) { + // http://jsperf.com/javascript-array-concat-vs-push/98 + results = concat.call(results, slice.call(arg)); + } else { + results.push(arg); + } + } + + return results; +}; + +swizzle.wrap = function (fn) { + return function () { + return fn(swizzle(arguments)); + }; +}; + + +/***/ }), +/* 19 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +module.exports = function isArrayish(obj) { + if (!obj) { + return false; + } + + return obj instanceof Array || Array.isArray(obj) || + (obj.length >= 0 && obj.splice instanceof Function); +}; + + +/***/ }), +/* 20 */ +/***/ (function(module, exports, __webpack_require__) { + +var conversions = __webpack_require__(6); +var route = __webpack_require__(21); + +var convert = {}; + +var models = Object.keys(conversions); + +function wrapRaw(fn) { + var wrappedFn = function (args) { + if (args === undefined || args === null) { + return args; + } + + if (arguments.length > 1) { + args = Array.prototype.slice.call(arguments); + } + + return fn(args); + }; + + // preserve .conversion property if there is one + if ('conversion' in fn) { + wrappedFn.conversion = fn.conversion; + } + + return wrappedFn; +} + +function wrapRounded(fn) { + var wrappedFn = function (args) { + if (args === undefined || args === null) { + return args; + } + + if (arguments.length > 1) { + args = Array.prototype.slice.call(arguments); + } + + var result = fn(args); + + // we're assuming the result is an array here. + // see notice in conversions.js; don't use box types + // in conversion functions. + if (typeof result === 'object') { + for (var len = result.length, i = 0; i < len; i++) { + result[i] = Math.round(result[i]); + } + } + + return result; + }; + + // preserve .conversion property if there is one + if ('conversion' in fn) { + wrappedFn.conversion = fn.conversion; + } + + return wrappedFn; +} + +models.forEach(function (fromModel) { + convert[fromModel] = {}; + + Object.defineProperty(convert[fromModel], 'channels', {value: conversions[fromModel].channels}); + Object.defineProperty(convert[fromModel], 'labels', {value: conversions[fromModel].labels}); + + var routes = route(fromModel); + var routeModels = Object.keys(routes); + + routeModels.forEach(function (toModel) { + var fn = routes[toModel]; + + convert[fromModel][toModel] = wrapRounded(fn); + convert[fromModel][toModel].raw = wrapRaw(fn); + }); +}); + +module.exports = convert; + + +/***/ }), +/* 21 */ +/***/ (function(module, exports, __webpack_require__) { + +var conversions = __webpack_require__(6); + +/* + this function routes a model to all other models. + + all functions that are routed have a property `.conversion` attached + to the returned synthetic function. This property is an array + of strings, each with the steps in between the 'from' and 'to' + color models (inclusive). + + conversions that are not possible simply are not included. +*/ + +function buildGraph() { + var graph = {}; + // https://jsperf.com/object-keys-vs-for-in-with-closure/3 + var models = Object.keys(conversions); + + for (var len = models.length, i = 0; i < len; i++) { + graph[models[i]] = { + // http://jsperf.com/1-vs-infinity + // micro-opt, but this is simple. + distance: -1, + parent: null + }; + } + + return graph; +} + +// https://en.wikipedia.org/wiki/Breadth-first_search +function deriveBFS(fromModel) { + var graph = buildGraph(); + var queue = [fromModel]; // unshift -> queue -> pop + + graph[fromModel].distance = 0; + + while (queue.length) { + var current = queue.pop(); + var adjacents = Object.keys(conversions[current]); + + for (var len = adjacents.length, i = 0; i < len; i++) { + var adjacent = adjacents[i]; + var node = graph[adjacent]; + + if (node.distance === -1) { + node.distance = graph[current].distance + 1; + node.parent = current; + queue.unshift(adjacent); + } + } + } + + return graph; +} + +function link(from, to) { + return function (args) { + return to(from(args)); + }; +} + +function wrapConversion(toModel, graph) { + var path = [graph[toModel].parent, toModel]; + var fn = conversions[graph[toModel].parent][toModel]; + + var cur = graph[toModel].parent; + while (graph[cur].parent) { + path.unshift(graph[cur].parent); + fn = link(conversions[graph[cur].parent][cur], fn); + cur = graph[cur].parent; + } + + fn.conversion = path; + return fn; +} + +module.exports = function (fromModel) { + var graph = deriveBFS(fromModel); + var conversion = {}; + + var models = Object.keys(graph); + for (var len = models.length, i = 0; i < len; i++) { + var toModel = models[i]; + var node = graph[toModel]; + + if (node.parent === null) { + // no possible conversion, or this node is the source model. + continue; + } + + conversion[toModel] = wrapConversion(toModel, graph); + } + + return conversion; +}; + + + +/***/ }), +/* 22 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); + +var _jquery = __webpack_require__(0); + +var _jquery2 = _interopRequireDefault(_jquery); + +var _ColorItem = __webpack_require__(2); + +var _ColorItem2 = _interopRequireDefault(_ColorItem); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + +/** + * Handles everything related to the colorpicker color + * @ignore + */ +var ColorHandler = function () { + /** + * @param {Colorpicker} colorpicker + */ + function ColorHandler(colorpicker) { + _classCallCheck(this, ColorHandler); + + /** + * @type {Colorpicker} + */ + this.colorpicker = colorpicker; + } + + /** + * @returns {*|String|ColorItem} + */ + + + _createClass(ColorHandler, [{ + key: 'bind', + value: function bind() { + // if the color option is set + if (this.colorpicker.options.color) { + this.color = this.createColor(this.colorpicker.options.color); + return; + } + + // if element[color] is empty and the input has a value + if (!this.color && !!this.colorpicker.inputHandler.getValue()) { + this.color = this.createColor(this.colorpicker.inputHandler.getValue(), this.colorpicker.options.autoInputFallback); + } + } + }, { + key: 'unbind', + value: function unbind() { + this.colorpicker.element.removeData('color'); + } + + /** + * Returns the color string from the input value or the 'data-color' attribute of the input or element. + * If empty, it returns the defaultValue parameter. + * + * @returns {String|*} + */ + + }, { + key: 'getColorString', + value: function getColorString() { + if (!this.hasColor()) { + return ''; + } + + return this.color.string(this.format); + } + + /** + * Sets the color value + * + * @param {String|ColorItem} val + */ + + }, { + key: 'setColorString', + value: function setColorString(val) { + var color = val ? this.createColor(val) : null; + + this.color = color ? color : null; + } + + /** + * Creates a new color using the widget instance options (fallbackColor, format). + * + * @fires Colorpicker#colorpickerInvalid + * @param {*} val + * @param {boolean} fallbackOnInvalid + * @returns {ColorItem} + */ + + }, { + key: 'createColor', + value: function createColor(val) { + var fallbackOnInvalid = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true; + + var color = new _ColorItem2.default(this.resolveColorDelegate(val), this.format); + + if (!color.isValid()) { + if (fallbackOnInvalid) { + color = this.getFallbackColor(); + } + + /** + * (Colorpicker) Fired when the color is invalid and the fallback color is going to be used. + * + * @event Colorpicker#colorpickerInvalid + */ + this.colorpicker.trigger('colorpickerInvalid', color, val); + } + + if (!this.isAlphaEnabled()) { + // Alpha is disabled + color.alpha = 1; + } + + return color; + } + }, { + key: 'getFallbackColor', + value: function getFallbackColor() { + if (this.fallback && this.fallback === this.color) { + return this.color; + } + + var fallback = this.resolveColorDelegate(this.fallback); + + var color = new _ColorItem2.default(fallback, this.format); + + if (!color.isValid()) { + console.warn('The fallback color is invalid. Falling back to the previous color or black if any.'); + return this.color ? this.color : new _ColorItem2.default('#000000', this.format); + } + + return color; + } + + /** + * @returns {ColorItem} + */ + + }, { + key: 'assureColor', + value: function assureColor() { + if (!this.hasColor()) { + this.color = this.getFallbackColor(); + } + + return this.color; + } + + /** + * Delegates the color resolution to the colorpicker extensions. + * + * @param {String|*} color + * @param {boolean} realColor if true, the color should resolve into a real (not named) color code + * @returns {ColorItem|String|*|null} + */ + + }, { + key: 'resolveColorDelegate', + value: function resolveColorDelegate(color) { + var realColor = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true; + + var extResolvedColor = false; + + _jquery2.default.each(this.colorpicker.extensions, function (name, ext) { + if (extResolvedColor !== false) { + // skip if resolved + return; + } + extResolvedColor = ext.resolveColor(color, realColor); + }); + + return extResolvedColor ? extResolvedColor : color; + } + + /** + * Checks if there is a color object, that it is valid and it is not a fallback + * @returns {boolean} + */ + + }, { + key: 'isInvalidColor', + value: function isInvalidColor() { + return !this.hasColor() || !this.color.isValid(); + } + + /** + * Returns true if the useAlpha option is exactly true, false otherwise + * @returns {boolean} + */ + + }, { + key: 'isAlphaEnabled', + value: function isAlphaEnabled() { + return this.colorpicker.options.useAlpha !== false; + } + + /** + * Returns true if the current color object is an instance of Color, false otherwise. + * @returns {boolean} + */ + + }, { + key: 'hasColor', + value: function hasColor() { + return this.color instanceof _ColorItem2.default; + } + }, { + key: 'fallback', + get: function get() { + return this.colorpicker.options.fallbackColor ? this.colorpicker.options.fallbackColor : this.hasColor() ? this.color : null; + } + + /** + * @returns {String|null} + */ + + }, { + key: 'format', + get: function get() { + if (this.colorpicker.options.format) { + return this.colorpicker.options.format; + } + + if (this.hasColor() && this.color.hasTransparency() && this.color.format.match(/^hex/)) { + return this.isAlphaEnabled() ? 'rgba' : 'hex'; + } + + if (this.hasColor()) { + return this.color.format; + } + + return 'rgb'; + } + + /** + * Internal color getter + * + * @type {ColorItem|null} + */ + + }, { + key: 'color', + get: function get() { + return this.colorpicker.element.data('color'); + } + + /** + * Internal color setter + * + * @ignore + * @param {ColorItem|null} value + */ + , + set: function set(value) { + this.colorpicker.element.data('color', value); + + if (value instanceof _ColorItem2.default && this.colorpicker.options.format === 'auto') { + // If format is 'auto', use the first parsed one from now on + this.colorpicker.options.format = this.color.format; + } + } + }]); + + return ColorHandler; +}(); + +exports.default = ColorHandler; +module.exports = exports.default; + +/***/ }), +/* 23 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); + +var _jquery = __webpack_require__(0); + +var _jquery2 = _interopRequireDefault(_jquery); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + +/** + * Handles everything related to the colorpicker UI + * @ignore + */ +var PickerHandler = function () { + /** + * @param {Colorpicker} colorpicker + */ + function PickerHandler(colorpicker) { + _classCallCheck(this, PickerHandler); + + /** + * @type {Colorpicker} + */ + this.colorpicker = colorpicker; + /** + * @type {jQuery} + */ + this.picker = null; + } + + _createClass(PickerHandler, [{ + key: 'bind', + value: function bind() { + /** + * @type {jQuery|HTMLElement} + */ + var picker = this.picker = (0, _jquery2.default)(this.options.template); + + if (this.options.customClass) { + picker.addClass(this.options.customClass); + } + + if (this.options.horizontal) { + picker.addClass('colorpicker-horizontal'); + } + + if (this._supportsAlphaBar()) { + this.options.useAlpha = true; + picker.addClass('colorpicker-with-alpha'); + } else { + this.options.useAlpha = false; + } + } + }, { + key: 'attach', + value: function attach() { + // Inject the colorpicker element into the DOM + var pickerParent = this.colorpicker.container ? this.colorpicker.container : null; + + if (pickerParent) { + this.picker.appendTo(pickerParent); + } + } + }, { + key: 'unbind', + value: function unbind() { + this.picker.remove(); + } + }, { + key: '_supportsAlphaBar', + value: function _supportsAlphaBar() { + return (this.options.useAlpha || this.colorpicker.colorHandler.hasColor() && this.color.hasTransparency()) && this.options.useAlpha !== false && (!this.options.format || this.options.format && !this.options.format.match(/^hex([36])?$/i)); + } + + /** + * Changes the color adjustment bars using the current color object information. + */ + + }, { + key: 'update', + value: function update() { + if (!this.colorpicker.colorHandler.hasColor()) { + return; + } + + var vertical = this.options.horizontal !== true, + slider = vertical ? this.options.sliders : this.options.slidersHorz; + + var saturationGuide = this.picker.find('.colorpicker-saturation .colorpicker-guide'), + hueGuide = this.picker.find('.colorpicker-hue .colorpicker-guide'), + alphaGuide = this.picker.find('.colorpicker-alpha .colorpicker-guide'); + + var hsva = this.color.toHsvaRatio(); + + // Set guides position + if (hueGuide.length) { + hueGuide.css(vertical ? 'top' : 'left', (vertical ? slider.hue.maxTop : slider.hue.maxLeft) * (1 - hsva.h)); + } + if (alphaGuide.length) { + alphaGuide.css(vertical ? 'top' : 'left', (vertical ? slider.alpha.maxTop : slider.alpha.maxLeft) * (1 - hsva.a)); + } + if (saturationGuide.length) { + saturationGuide.css({ + 'top': slider.saturation.maxTop - hsva.v * slider.saturation.maxTop, + 'left': hsva.s * slider.saturation.maxLeft + }); + } + + // Set saturation hue background + this.picker.find('.colorpicker-saturation').css('backgroundColor', this.color.getCloneHueOnly().toHexString()); // we only need hue + + // Set alpha color gradient + var hexColor = this.color.toHexString(); + + var alphaBg = ''; + + if (this.options.horizontal) { + alphaBg = 'linear-gradient(to right, ' + hexColor + ' 0%, transparent 100%)'; + } else { + alphaBg = 'linear-gradient(to bottom, ' + hexColor + ' 0%, transparent 100%)'; + } + + this.picker.find('.colorpicker-alpha-color').css('background', alphaBg); + } + }, { + key: 'options', + get: function get() { + return this.colorpicker.options; + } + }, { + key: 'color', + get: function get() { + return this.colorpicker.colorHandler.color; + } + }]); + + return PickerHandler; +}(); + +exports.default = PickerHandler; +module.exports = exports.default; + +/***/ }), +/* 24 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +/** + * Handles everything related to the colorpicker addon + * @ignore + */ + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + +var AddonHandler = function () { + /** + * @param {Colorpicker} colorpicker + */ + function AddonHandler(colorpicker) { + _classCallCheck(this, AddonHandler); + + /** + * @type {Colorpicker} + */ + this.colorpicker = colorpicker; + /** + * @type {jQuery} + */ + this.addon = null; + } + + _createClass(AddonHandler, [{ + key: 'hasAddon', + value: function hasAddon() { + return !!this.addon; + } + }, { + key: 'bind', + value: function bind() { + /** + * @type {*|jQuery} + */ + this.addon = this.colorpicker.options.addon ? this.colorpicker.element.find(this.colorpicker.options.addon) : null; + + if (this.addon && this.addon.length === 0) { + // not found + this.addon = null; + } + } + }, { + key: 'unbind', + value: function unbind() { + if (this.hasAddon()) { + this.addon.off('.colorpicker'); + } + } + + /** + * If the addon element is present, its background color is updated + */ + + }, { + key: 'update', + value: function update() { + if (!this.colorpicker.colorHandler.hasColor() || !this.hasAddon()) { + return; + } + + var colorStr = this.colorpicker.colorHandler.getColorString(); + + var styles = { 'background': colorStr }; + + var icn = this.addon.find('i').eq(0); + + if (icn.length > 0) { + icn.css(styles); + } else { + this.addon.css(styles); + } + } + }]); + + return AddonHandler; +}(); + +exports.default = AddonHandler; +module.exports = exports.default; + +/***/ }) +/******/ ]); +}); +//# sourceMappingURL=bootstrap-colorpicker.js.map \ No newline at end of file diff --git a/hal-core/resources/web/js/lib/bootstrap-colorpicker.min.js b/hal-core/resources/web/js/lib/bootstrap-colorpicker.min.js new file mode 100644 index 00000000..bfdbed0c --- /dev/null +++ b/hal-core/resources/web/js/lib/bootstrap-colorpicker.min.js @@ -0,0 +1,10 @@ +/*! + * Bootstrap Colorpicker - Bootstrap Colorpicker is a modular color picker plugin for Bootstrap 4. + * @package bootstrap-colorpicker + * @version v3.2.0 + * @license MIT + * @link https://itsjavi.com/bootstrap-colorpicker/ + * @link https://github.com/itsjavi/bootstrap-colorpicker.git + */ +(function webpackUniversalModuleDefinition(root,factory){if(typeof exports==="object"&&typeof module==="object")module.exports=factory(require("jquery"));else if(typeof define==="function"&&define.amd)define("bootstrap-colorpicker",["jquery"],factory);else if(typeof exports==="object")exports["bootstrap-colorpicker"]=factory(require("jquery"));else root["bootstrap-colorpicker"]=factory(root["jQuery"])})(window,function(__WEBPACK_EXTERNAL_MODULE__0__){return function(modules){var installedModules={};function __webpack_require__(moduleId){if(installedModules[moduleId]){return installedModules[moduleId].exports}var module=installedModules[moduleId]={i:moduleId,l:false,exports:{}};modules[moduleId].call(module.exports,module,module.exports,__webpack_require__);module.l=true;return module.exports}__webpack_require__.m=modules;__webpack_require__.c=installedModules;__webpack_require__.d=function(exports,name,getter){if(!__webpack_require__.o(exports,name)){Object.defineProperty(exports,name,{enumerable:true,get:getter})}};__webpack_require__.r=function(exports){if(typeof Symbol!=="undefined"&&Symbol.toStringTag){Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"})}Object.defineProperty(exports,"__esModule",{value:true})};__webpack_require__.t=function(value,mode){if(mode&1)value=__webpack_require__(value);if(mode&8)return value;if(mode&4&&typeof value==="object"&&value&&value.__esModule)return value;var ns=Object.create(null);__webpack_require__.r(ns);Object.defineProperty(ns,"default",{enumerable:true,value});if(mode&2&&typeof value!="string")for(var key in value)__webpack_require__.d(ns,key,function(key){return value[key]}.bind(null,key));return ns};__webpack_require__.n=function(module){var getter=module&&module.__esModule?function getDefault(){return module["default"]}:function getModuleExports(){return module};__webpack_require__.d(getter,"a",getter);return getter};__webpack_require__.o=function(object,property){return Object.prototype.hasOwnProperty.call(object,property)};__webpack_require__.p="";return __webpack_require__(__webpack_require__.s=7)}([function(module,exports){module.exports=__WEBPACK_EXTERNAL_MODULE__0__},function(module,exports,__webpack_require__){"use strict";Object.defineProperty(exports,"__esModule",{value:true});var _createClass=function(){function defineProperties(target,props){for(var i=0;i1&&arguments[1]!==undefined?arguments[1]:{};_classCallCheck(this,Extension);this.colorpicker=colorpicker;this.options=options;if(!(this.colorpicker.element&&this.colorpicker.element.length)){throw new Error("Extension: this.colorpicker.element is not valid")}this.colorpicker.element.on("colorpickerCreate.colorpicker-ext",_jquery2.default.proxy(this.onCreate,this));this.colorpicker.element.on("colorpickerDestroy.colorpicker-ext",_jquery2.default.proxy(this.onDestroy,this));this.colorpicker.element.on("colorpickerUpdate.colorpicker-ext",_jquery2.default.proxy(this.onUpdate,this));this.colorpicker.element.on("colorpickerChange.colorpicker-ext",_jquery2.default.proxy(this.onChange,this));this.colorpicker.element.on("colorpickerInvalid.colorpicker-ext",_jquery2.default.proxy(this.onInvalid,this));this.colorpicker.element.on("colorpickerShow.colorpicker-ext",_jquery2.default.proxy(this.onShow,this));this.colorpicker.element.on("colorpickerHide.colorpicker-ext",_jquery2.default.proxy(this.onHide,this));this.colorpicker.element.on("colorpickerEnable.colorpicker-ext",_jquery2.default.proxy(this.onEnable,this));this.colorpicker.element.on("colorpickerDisable.colorpicker-ext",_jquery2.default.proxy(this.onDisable,this))}_createClass(Extension,[{key:"resolveColor",value:function resolveColor(color){var realColor=arguments.length>1&&arguments[1]!==undefined?arguments[1]:true;return false}},{key:"onCreate",value:function onCreate(event){}},{key:"onDestroy",value:function onDestroy(event){this.colorpicker.element.off(".colorpicker-ext")}},{key:"onUpdate",value:function onUpdate(event){}},{key:"onChange",value:function onChange(event){}},{key:"onInvalid",value:function onInvalid(event){}},{key:"onHide",value:function onHide(event){}},{key:"onShow",value:function onShow(event){}},{key:"onDisable",value:function onDisable(event){}},{key:"onEnable",value:function onEnable(event){}}]);return Extension}();exports.default=Extension;module.exports=exports.default},function(module,exports,__webpack_require__){"use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.ColorItem=exports.HSVAColor=undefined;var _createClass=function(){function defineProperties(target,props){for(var i=0;i1?_len-1:0),_key=1;_key<_len;_key++){args[_key-1]=arguments[_key]}if(arguments.length===0){return this._color}var result=this._color[fn].apply(this._color,args);if(!(result instanceof _color2.default)){return result}return new ColorItem(result,this.format)}},{key:"original",get:function get(){return this._original}}],[{key:"HSVAColor",get:function get(){return HSVAColor}}]);function ColorItem(){var color=arguments.length>0&&arguments[0]!==undefined?arguments[0]:null;var format=arguments.length>1&&arguments[1]!==undefined?arguments[1]:null;_classCallCheck(this,ColorItem);this.replace(color,format)}_createClass(ColorItem,[{key:"replace",value:function replace(color){var format=arguments.length>1&&arguments[1]!==undefined?arguments[1]:null;format=ColorItem.sanitizeFormat(format);this._original={color,format,valid:true};this._color=ColorItem.parse(color);if(this._color===null){this._color=(0,_color2.default)();this._original.valid=false;return}this._format=format?format:ColorItem.isHex(color)?"hex":this._color.model}},{key:"isValid",value:function isValid(){return this._original.valid===true}},{key:"setHueRatio",value:function setHueRatio(h){this.hue=(1-h)*360}},{key:"setSaturationRatio",value:function setSaturationRatio(s){this.saturation=s*100}},{key:"setValueRatio",value:function setValueRatio(v){this.value=(1-v)*100}},{key:"setAlphaRatio",value:function setAlphaRatio(a){this.alpha=1-a}},{key:"isDesaturated",value:function isDesaturated(){return this.saturation===0}},{key:"isTransparent",value:function isTransparent(){return this.alpha===0}},{key:"hasTransparency",value:function hasTransparency(){return this.hasAlpha()&&this.alpha<1}},{key:"hasAlpha",value:function hasAlpha(){return!isNaN(this.alpha)}},{key:"toObject",value:function toObject(){return new HSVAColor(this.hue,this.saturation,this.value,this.alpha)}},{key:"toHsva",value:function toHsva(){return this.toObject()}},{key:"toHsvaRatio",value:function toHsvaRatio(){return new HSVAColor(this.hue/360,this.saturation/100,this.value/100,this.alpha)}},{key:"toString",value:function toString(){return this.string()}},{key:"string",value:function string(){var format=arguments.length>0&&arguments[0]!==undefined?arguments[0]:null;format=ColorItem.sanitizeFormat(format?format:this.format);if(!format){return this._color.round().string()}if(this._color[format]===undefined){throw new Error("Unsupported color format: '"+format+"'")}var str=this._color[format]();return str.round?str.round().string():str}},{key:"equals",value:function equals(color){color=color instanceof ColorItem?color:new ColorItem(color);if(!color.isValid()||!this.isValid()){return false}return this.hue===color.hue&&this.saturation===color.saturation&&this.value===color.value&&this.alpha===color.alpha}},{key:"getClone",value:function getClone(){return new ColorItem(this._color,this.format)}},{key:"getCloneHueOnly",value:function getCloneHueOnly(){return new ColorItem([this.hue,100,100,1],this.format)}},{key:"getCloneOpaque",value:function getCloneOpaque(){return new ColorItem(this._color.alpha(1),this.format)}},{key:"toRgbString",value:function toRgbString(){return this.string("rgb")}},{key:"toHexString",value:function toHexString(){return this.string("hex")}},{key:"toHslString",value:function toHslString(){return this.string("hsl")}},{key:"isDark",value:function isDark(){return this._color.isDark()}},{key:"isLight",value:function isLight(){return this._color.isLight()}},{key:"generate",value:function generate(formula){var hues=[];if(Array.isArray(formula)){hues=formula}else if(!ColorItem.colorFormulas.hasOwnProperty(formula)){throw new Error("No color formula found with the name '"+formula+"'.")}else{hues=ColorItem.colorFormulas[formula]}var colors=[],mainColor=this._color,format=this.format;hues.forEach(function(hue){var levels=[hue?(mainColor.hue()+hue)%360:mainColor.hue(),mainColor.saturationv(),mainColor.value(),mainColor.alpha()];colors.push(new ColorItem(levels,format))});return colors}},{key:"hue",get:function get(){return this._color.hue()},set:function set(value){this._color=this._color.hue(value)}},{key:"saturation",get:function get(){return this._color.saturationv()},set:function set(value){this._color=this._color.saturationv(value)}},{key:"value",get:function get(){return this._color.value()},set:function set(value){this._color=this._color.value(value)}},{key:"alpha",get:function get(){var a=this._color.alpha();return isNaN(a)?1:a},set:function set(value){this._color=this._color.alpha(Math.round(value*100)/100)}},{key:"format",get:function get(){return this._format?this._format:this._color.model},set:function set(value){this._format=ColorItem.sanitizeFormat(value)}}],[{key:"parse",value:function parse(color){if(color instanceof _color2.default){return color}if(color instanceof ColorItem){return color._color}var format=null;if(color instanceof HSVAColor){color=[color.h,color.s,color.v,isNaN(color.a)?1:color.a]}else{color=ColorItem.sanitizeString(color)}if(color===null){return null}if(Array.isArray(color)){format="hsv"}try{return(0,_color2.default)(color,format)}catch(e){return null}}},{key:"sanitizeString",value:function sanitizeString(str){if(!(typeof str==="string"||str instanceof String)){return str}if(str.match(/^[0-9a-f]{2,}$/i)){return"#"+str}if(str.toLowerCase()==="transparent"){return"#FFFFFF00"}return str}},{key:"isHex",value:function isHex(str){if(!(typeof str==="string"||str instanceof String)){return false}return!!str.match(/^#?[0-9a-f]{2,}$/i)}},{key:"sanitizeFormat",value:function sanitizeFormat(format){switch(format){case"hex":case"hex3":case"hex4":case"hex6":case"hex8":return"hex";case"rgb":case"rgba":case"keyword":case"name":return"rgb";case"hsl":case"hsla":case"hsv":case"hsva":case"hwb":case"hwba":return"hsl";default:return""}}}]);return ColorItem}();ColorItem.colorFormulas={complementary:[180],triad:[0,120,240],tetrad:[0,90,180,270],splitcomplement:[0,72,216]};exports.default=ColorItem;exports.HSVAColor=HSVAColor;exports.ColorItem=ColorItem},function(module,exports,__webpack_require__){"use strict";Object.defineProperty(exports,"__esModule",{value:true});var sassVars={bar_size_short:16,base_margin:6,columns:6};var sliderSize=sassVars.bar_size_short*sassVars.columns+sassVars.base_margin*(sassVars.columns-1);exports.default={customClass:null,color:false,fallbackColor:false,format:"auto",horizontal:false,inline:false,container:false,popover:{animation:true,placement:"bottom",fallbackPlacement:"flip"},debug:false,input:"input",addon:".colorpicker-input-addon",autoInputFallback:true,useHashPrefix:true,useAlpha:true,template:'
\n
\n
\n
\n
\n \n
\n
',extensions:[{name:"preview",options:{showText:true}}],sliders:{saturation:{selector:".colorpicker-saturation",maxLeft:sliderSize,maxTop:sliderSize,callLeft:"setSaturationRatio",callTop:"setValueRatio"},hue:{selector:".colorpicker-hue",maxLeft:0,maxTop:sliderSize,callLeft:false,callTop:"setHueRatio"},alpha:{selector:".colorpicker-alpha",childSelector:".colorpicker-alpha-color",maxLeft:0,maxTop:sliderSize,callLeft:false,callTop:"setAlphaRatio"}},slidersHorz:{saturation:{selector:".colorpicker-saturation",maxLeft:sliderSize,maxTop:sliderSize,callLeft:"setSaturationRatio",callTop:"setValueRatio"},hue:{selector:".colorpicker-hue",maxLeft:sliderSize,maxTop:0,callLeft:"setHueRatio",callTop:false},alpha:{selector:".colorpicker-alpha",childSelector:".colorpicker-alpha-color",maxLeft:sliderSize,maxTop:0,callLeft:"setAlphaRatio",callTop:false}}};module.exports=exports.default},function(module,exports,__webpack_require__){"use strict";Object.defineProperty(exports,"__esModule",{value:true});var _typeof=typeof Symbol==="function"&&typeof Symbol.iterator==="symbol"?function(obj){return typeof obj}:function(obj){return obj&&typeof Symbol==="function"&&obj.constructor===Symbol&&obj!==Symbol.prototype?"symbol":typeof obj};var _createClass=function(){function defineProperties(target,props){for(var i=0;i1&&arguments[1]!==undefined?arguments[1]:{};_classCallCheck(this,Palette);var _this=_possibleConstructorReturn(this,(Palette.__proto__||Object.getPrototypeOf(Palette)).call(this,colorpicker,_jquery2.default.extend(true,{},defaults,options)));if(!Array.isArray(_this.options.colors)&&_typeof(_this.options.colors)!=="object"){_this.options.colors=null}return _this}_createClass(Palette,[{key:"getLength",value:function getLength(){if(!this.options.colors){return 0}if(Array.isArray(this.options.colors)){return this.options.colors.length}if(_typeof(this.options.colors)==="object"){return Object.keys(this.options.colors).length}return 0}},{key:"resolveColor",value:function resolveColor(color){var realColor=arguments.length>1&&arguments[1]!==undefined?arguments[1]:true;if(this.getLength()<=0){return false}if(Array.isArray(this.options.colors)){if(this.options.colors.indexOf(color)>=0){return color}if(this.options.colors.indexOf(color.toUpperCase())>=0){return color.toUpperCase()}if(this.options.colors.indexOf(color.toLowerCase())>=0){return color.toLowerCase()}return false}if(_typeof(this.options.colors)!=="object"){return false}if(!this.options.namesAsValues||realColor){return this.getValue(color,false)}return this.getName(color,this.getName("#"+color))}},{key:"getName",value:function getName(value){var defaultValue=arguments.length>1&&arguments[1]!==undefined?arguments[1]:false;if(!(typeof value==="string")||!this.options.colors){return defaultValue}for(var name in this.options.colors){if(!this.options.colors.hasOwnProperty(name)){continue}if(this.options.colors[name].toLowerCase()===value.toLowerCase()){return name}}return defaultValue}},{key:"getValue",value:function getValue(name){var defaultValue=arguments.length>1&&arguments[1]!==undefined?arguments[1]:false;if(!(typeof name==="string")||!this.options.colors){return defaultValue}if(this.options.colors.hasOwnProperty(name)){return this.options.colors[name]}return defaultValue}}]);return Palette}(_Extension3.default);exports.default=Palette;module.exports=exports.default},function(module,exports,__webpack_require__){"use strict";module.exports={aliceblue:[240,248,255],antiquewhite:[250,235,215],aqua:[0,255,255],aquamarine:[127,255,212],azure:[240,255,255],beige:[245,245,220],bisque:[255,228,196],black:[0,0,0],blanchedalmond:[255,235,205],blue:[0,0,255],blueviolet:[138,43,226],brown:[165,42,42],burlywood:[222,184,135],cadetblue:[95,158,160],chartreuse:[127,255,0],chocolate:[210,105,30],coral:[255,127,80],cornflowerblue:[100,149,237],cornsilk:[255,248,220],crimson:[220,20,60],cyan:[0,255,255],darkblue:[0,0,139],darkcyan:[0,139,139],darkgoldenrod:[184,134,11],darkgray:[169,169,169],darkgreen:[0,100,0],darkgrey:[169,169,169],darkkhaki:[189,183,107],darkmagenta:[139,0,139],darkolivegreen:[85,107,47],darkorange:[255,140,0],darkorchid:[153,50,204],darkred:[139,0,0],darksalmon:[233,150,122],darkseagreen:[143,188,143],darkslateblue:[72,61,139],darkslategray:[47,79,79],darkslategrey:[47,79,79],darkturquoise:[0,206,209],darkviolet:[148,0,211],deeppink:[255,20,147],deepskyblue:[0,191,255],dimgray:[105,105,105],dimgrey:[105,105,105],dodgerblue:[30,144,255],firebrick:[178,34,34],floralwhite:[255,250,240],forestgreen:[34,139,34],fuchsia:[255,0,255],gainsboro:[220,220,220],ghostwhite:[248,248,255],gold:[255,215,0],goldenrod:[218,165,32],gray:[128,128,128],green:[0,128,0],greenyellow:[173,255,47],grey:[128,128,128],honeydew:[240,255,240],hotpink:[255,105,180],indianred:[205,92,92],indigo:[75,0,130],ivory:[255,255,240],khaki:[240,230,140],lavender:[230,230,250],lavenderblush:[255,240,245],lawngreen:[124,252,0],lemonchiffon:[255,250,205],lightblue:[173,216,230],lightcoral:[240,128,128],lightcyan:[224,255,255],lightgoldenrodyellow:[250,250,210],lightgray:[211,211,211],lightgreen:[144,238,144],lightgrey:[211,211,211],lightpink:[255,182,193],lightsalmon:[255,160,122],lightseagreen:[32,178,170],lightskyblue:[135,206,250],lightslategray:[119,136,153],lightslategrey:[119,136,153],lightsteelblue:[176,196,222],lightyellow:[255,255,224],lime:[0,255,0],limegreen:[50,205,50],linen:[250,240,230],magenta:[255,0,255],maroon:[128,0,0],mediumaquamarine:[102,205,170],mediumblue:[0,0,205],mediumorchid:[186,85,211],mediumpurple:[147,112,219],mediumseagreen:[60,179,113],mediumslateblue:[123,104,238],mediumspringgreen:[0,250,154],mediumturquoise:[72,209,204],mediumvioletred:[199,21,133],midnightblue:[25,25,112],mintcream:[245,255,250],mistyrose:[255,228,225],moccasin:[255,228,181],navajowhite:[255,222,173],navy:[0,0,128],oldlace:[253,245,230],olive:[128,128,0],olivedrab:[107,142,35],orange:[255,165,0],orangered:[255,69,0],orchid:[218,112,214],palegoldenrod:[238,232,170],palegreen:[152,251,152],paleturquoise:[175,238,238],palevioletred:[219,112,147],papayawhip:[255,239,213],peachpuff:[255,218,185],peru:[205,133,63],pink:[255,192,203],plum:[221,160,221],powderblue:[176,224,230],purple:[128,0,128],rebeccapurple:[102,51,153],red:[255,0,0],rosybrown:[188,143,143],royalblue:[65,105,225],saddlebrown:[139,69,19],salmon:[250,128,114],sandybrown:[244,164,96],seagreen:[46,139,87],seashell:[255,245,238],sienna:[160,82,45],silver:[192,192,192],skyblue:[135,206,235],slateblue:[106,90,205],slategray:[112,128,144],slategrey:[112,128,144],snow:[255,250,250],springgreen:[0,255,127],steelblue:[70,130,180],tan:[210,180,140],teal:[0,128,128],thistle:[216,191,216],tomato:[255,99,71],turquoise:[64,224,208],violet:[238,130,238],wheat:[245,222,179],white:[255,255,255],whitesmoke:[245,245,245],yellow:[255,255,0],yellowgreen:[154,205,50]}},function(module,exports,__webpack_require__){var cssKeywords=__webpack_require__(5);var reverseKeywords={};for(var key in cssKeywords){if(cssKeywords.hasOwnProperty(key)){reverseKeywords[cssKeywords[key]]=key}}var convert=module.exports={rgb:{channels:3,labels:"rgb"},hsl:{channels:3,labels:"hsl"},hsv:{channels:3,labels:"hsv"},hwb:{channels:3,labels:"hwb"},cmyk:{channels:4,labels:"cmyk"},xyz:{channels:3,labels:"xyz"},lab:{channels:3,labels:"lab"},lch:{channels:3,labels:"lch"},hex:{channels:1,labels:["hex"]},keyword:{channels:1,labels:["keyword"]},ansi16:{channels:1,labels:["ansi16"]},ansi256:{channels:1,labels:["ansi256"]},hcg:{channels:3,labels:["h","c","g"]},apple:{channels:3,labels:["r16","g16","b16"]},gray:{channels:1,labels:["gray"]}};for(var model in convert){if(convert.hasOwnProperty(model)){if(!("channels"in convert[model])){throw new Error("missing channels property: "+model)}if(!("labels"in convert[model])){throw new Error("missing channel labels property: "+model)}if(convert[model].labels.length!==convert[model].channels){throw new Error("channel and label counts mismatch: "+model)}var channels=convert[model].channels;var labels=convert[model].labels;delete convert[model].channels;delete convert[model].labels;Object.defineProperty(convert[model],"channels",{value:channels});Object.defineProperty(convert[model],"labels",{value:labels})}}convert.rgb.hsl=function(rgb){var r=rgb[0]/255;var g=rgb[1]/255;var b=rgb[2]/255;var min=Math.min(r,g,b);var max=Math.max(r,g,b);var delta=max-min;var h;var s;var l;if(max===min){h=0}else if(r===max){h=(g-b)/delta}else if(g===max){h=2+(b-r)/delta}else if(b===max){h=4+(r-g)/delta}h=Math.min(h*60,360);if(h<0){h+=360}l=(min+max)/2;if(max===min){s=0}else if(l<=.5){s=delta/(max+min)}else{s=delta/(2-max-min)}return[h,s*100,l*100]};convert.rgb.hsv=function(rgb){var rdif;var gdif;var bdif;var h;var s;var r=rgb[0]/255;var g=rgb[1]/255;var b=rgb[2]/255;var v=Math.max(r,g,b);var diff=v-Math.min(r,g,b);var diffc=function(c){return(v-c)/6/diff+1/2};if(diff===0){h=s=0}else{s=diff/v;rdif=diffc(r);gdif=diffc(g);bdif=diffc(b);if(r===v){h=bdif-gdif}else if(g===v){h=1/3+rdif-bdif}else if(b===v){h=2/3+gdif-rdif}if(h<0){h+=1}else if(h>1){h-=1}}return[h*360,s*100,v*100]};convert.rgb.hwb=function(rgb){var r=rgb[0];var g=rgb[1];var b=rgb[2];var h=convert.rgb.hsl(rgb)[0];var w=1/255*Math.min(r,Math.min(g,b));b=1-1/255*Math.max(r,Math.max(g,b));return[h,w*100,b*100]};convert.rgb.cmyk=function(rgb){var r=rgb[0]/255;var g=rgb[1]/255;var b=rgb[2]/255;var c;var m;var y;var k;k=Math.min(1-r,1-g,1-b);c=(1-r-k)/(1-k)||0;m=(1-g-k)/(1-k)||0;y=(1-b-k)/(1-k)||0;return[c*100,m*100,y*100,k*100]};function comparativeDistance(x,y){return Math.pow(x[0]-y[0],2)+Math.pow(x[1]-y[1],2)+Math.pow(x[2]-y[2],2)}convert.rgb.keyword=function(rgb){var reversed=reverseKeywords[rgb];if(reversed){return reversed}var currentClosestDistance=Infinity;var currentClosestKeyword;for(var keyword in cssKeywords){if(cssKeywords.hasOwnProperty(keyword)){var value=cssKeywords[keyword];var distance=comparativeDistance(rgb,value);if(distance.04045?Math.pow((r+.055)/1.055,2.4):r/12.92;g=g>.04045?Math.pow((g+.055)/1.055,2.4):g/12.92;b=b>.04045?Math.pow((b+.055)/1.055,2.4):b/12.92;var x=r*.4124+g*.3576+b*.1805;var y=r*.2126+g*.7152+b*.0722;var z=r*.0193+g*.1192+b*.9505;return[x*100,y*100,z*100]};convert.rgb.lab=function(rgb){var xyz=convert.rgb.xyz(rgb);var x=xyz[0];var y=xyz[1];var z=xyz[2];var l;var a;var b;x/=95.047;y/=100;z/=108.883;x=x>.008856?Math.pow(x,1/3):7.787*x+16/116;y=y>.008856?Math.pow(y,1/3):7.787*y+16/116;z=z>.008856?Math.pow(z,1/3):7.787*z+16/116;l=116*y-16;a=500*(x-y);b=200*(y-z);return[l,a,b]};convert.hsl.rgb=function(hsl){var h=hsl[0]/360;var s=hsl[1]/100;var l=hsl[2]/100;var t1;var t2;var t3;var rgb;var val;if(s===0){val=l*255;return[val,val,val]}if(l<.5){t2=l*(1+s)}else{t2=l+s-l*s}t1=2*l-t2;rgb=[0,0,0];for(var i=0;i<3;i++){t3=h+1/3*-(i-1);if(t3<0){t3++}if(t3>1){t3--}if(6*t3<1){val=t1+(t2-t1)*6*t3}else if(2*t3<1){val=t2}else if(3*t3<2){val=t1+(t2-t1)*(2/3-t3)*6}else{val=t1}rgb[i]=val*255}return rgb};convert.hsl.hsv=function(hsl){var h=hsl[0];var s=hsl[1]/100;var l=hsl[2]/100;var smin=s;var lmin=Math.max(l,.01);var sv;var v;l*=2;s*=l<=1?l:2-l;smin*=lmin<=1?lmin:2-lmin;v=(l+s)/2;sv=l===0?2*smin/(lmin+smin):2*s/(l+s);return[h,sv*100,v*100]};convert.hsv.rgb=function(hsv){var h=hsv[0]/60;var s=hsv[1]/100;var v=hsv[2]/100;var hi=Math.floor(h)%6;var f=h-Math.floor(h);var p=255*v*(1-s);var q=255*v*(1-s*f);var t=255*v*(1-s*(1-f));v*=255;switch(hi){case 0:return[v,t,p];case 1:return[q,v,p];case 2:return[p,v,t];case 3:return[p,q,v];case 4:return[t,p,v];case 5:return[v,p,q]}};convert.hsv.hsl=function(hsv){var h=hsv[0];var s=hsv[1]/100;var v=hsv[2]/100;var vmin=Math.max(v,.01);var lmin;var sl;var l;l=(2-s)*v;lmin=(2-s)*vmin;sl=s*vmin;sl/=lmin<=1?lmin:2-lmin;sl=sl||0;l/=2;return[h,sl*100,l*100]};convert.hwb.rgb=function(hwb){var h=hwb[0]/360;var wh=hwb[1]/100;var bl=hwb[2]/100;var ratio=wh+bl;var i;var v;var f;var n;if(ratio>1){wh/=ratio;bl/=ratio}i=Math.floor(6*h);v=1-bl;f=6*h-i;if((i&1)!==0){f=1-f}n=wh+f*(v-wh);var r;var g;var b;switch(i){default:case 6:case 0:r=v;g=n;b=wh;break;case 1:r=n;g=v;b=wh;break;case 2:r=wh;g=v;b=n;break;case 3:r=wh;g=n;b=v;break;case 4:r=n;g=wh;b=v;break;case 5:r=v;g=wh;b=n;break}return[r*255,g*255,b*255]};convert.cmyk.rgb=function(cmyk){var c=cmyk[0]/100;var m=cmyk[1]/100;var y=cmyk[2]/100;var k=cmyk[3]/100;var r;var g;var b;r=1-Math.min(1,c*(1-k)+k);g=1-Math.min(1,m*(1-k)+k);b=1-Math.min(1,y*(1-k)+k);return[r*255,g*255,b*255]};convert.xyz.rgb=function(xyz){var x=xyz[0]/100;var y=xyz[1]/100;var z=xyz[2]/100;var r;var g;var b;r=x*3.2406+y*-1.5372+z*-.4986;g=x*-.9689+y*1.8758+z*.0415;b=x*.0557+y*-.204+z*1.057;r=r>.0031308?1.055*Math.pow(r,1/2.4)-.055:r*12.92;g=g>.0031308?1.055*Math.pow(g,1/2.4)-.055:g*12.92;b=b>.0031308?1.055*Math.pow(b,1/2.4)-.055:b*12.92;r=Math.min(Math.max(0,r),1);g=Math.min(Math.max(0,g),1);b=Math.min(Math.max(0,b),1);return[r*255,g*255,b*255]};convert.xyz.lab=function(xyz){var x=xyz[0];var y=xyz[1];var z=xyz[2];var l;var a;var b;x/=95.047;y/=100;z/=108.883;x=x>.008856?Math.pow(x,1/3):7.787*x+16/116;y=y>.008856?Math.pow(y,1/3):7.787*y+16/116;z=z>.008856?Math.pow(z,1/3):7.787*z+16/116;l=116*y-16;a=500*(x-y);b=200*(y-z);return[l,a,b]};convert.lab.xyz=function(lab){var l=lab[0];var a=lab[1];var b=lab[2];var x;var y;var z;y=(l+16)/116;x=a/500+y;z=y-b/200;var y2=Math.pow(y,3);var x2=Math.pow(x,3);var z2=Math.pow(z,3);y=y2>.008856?y2:(y-16/116)/7.787;x=x2>.008856?x2:(x-16/116)/7.787;z=z2>.008856?z2:(z-16/116)/7.787;x*=95.047;y*=100;z*=108.883;return[x,y,z]};convert.lab.lch=function(lab){var l=lab[0];var a=lab[1];var b=lab[2];var hr;var h;var c;hr=Math.atan2(b,a);h=hr*360/2/Math.PI;if(h<0){h+=360}c=Math.sqrt(a*a+b*b);return[l,c,h]};convert.lch.lab=function(lch){var l=lch[0];var c=lch[1];var h=lch[2];var a;var b;var hr;hr=h/360*2*Math.PI;a=c*Math.cos(hr);b=c*Math.sin(hr);return[l,a,b]};convert.rgb.ansi16=function(args){var r=args[0];var g=args[1];var b=args[2];var value=1 in arguments?arguments[1]:convert.rgb.hsv(args)[2];value=Math.round(value/50);if(value===0){return 30}var ansi=30+(Math.round(b/255)<<2|Math.round(g/255)<<1|Math.round(r/255));if(value===2){ansi+=60}return ansi};convert.hsv.ansi16=function(args){return convert.rgb.ansi16(convert.hsv.rgb(args),args[2])};convert.rgb.ansi256=function(args){var r=args[0];var g=args[1];var b=args[2];if(r===g&&g===b){if(r<8){return 16}if(r>248){return 231}return Math.round((r-8)/247*24)+232}var ansi=16+36*Math.round(r/255*5)+6*Math.round(g/255*5)+Math.round(b/255*5);return ansi};convert.ansi16.rgb=function(args){var color=args%10;if(color===0||color===7){if(args>50){color+=3.5}color=color/10.5*255;return[color,color,color]}var mult=(~~(args>50)+1)*.5;var r=(color&1)*mult*255;var g=(color>>1&1)*mult*255;var b=(color>>2&1)*mult*255;return[r,g,b]};convert.ansi256.rgb=function(args){if(args>=232){var c=(args-232)*10+8;return[c,c,c]}args-=16;var rem;var r=Math.floor(args/36)/5*255;var g=Math.floor((rem=args%36)/6)/5*255;var b=rem%6/5*255;return[r,g,b]};convert.rgb.hex=function(args){var integer=((Math.round(args[0])&255)<<16)+((Math.round(args[1])&255)<<8)+(Math.round(args[2])&255);var string=integer.toString(16).toUpperCase();return"000000".substring(string.length)+string};convert.hex.rgb=function(args){var match=args.toString(16).match(/[a-f0-9]{6}|[a-f0-9]{3}/i);if(!match){return[0,0,0]}var colorString=match[0];if(match[0].length===3){colorString=colorString.split("").map(function(char){return char+char}).join("")}var integer=parseInt(colorString,16);var r=integer>>16&255;var g=integer>>8&255;var b=integer&255;return[r,g,b]};convert.rgb.hcg=function(rgb){var r=rgb[0]/255;var g=rgb[1]/255;var b=rgb[2]/255;var max=Math.max(Math.max(r,g),b);var min=Math.min(Math.min(r,g),b);var chroma=max-min;var grayscale;var hue;if(chroma<1){grayscale=min/(1-chroma)}else{grayscale=0}if(chroma<=0){hue=0}else if(max===r){hue=(g-b)/chroma%6}else if(max===g){hue=2+(b-r)/chroma}else{hue=4+(r-g)/chroma+4}hue/=6;hue%=1;return[hue*360,chroma*100,grayscale*100]};convert.hsl.hcg=function(hsl){var s=hsl[1]/100;var l=hsl[2]/100;var c=1;var f=0;if(l<.5){c=2*s*l}else{c=2*s*(1-l)}if(c<1){f=(l-.5*c)/(1-c)}return[hsl[0],c*100,f*100]};convert.hsv.hcg=function(hsv){var s=hsv[1]/100;var v=hsv[2]/100;var c=s*v;var f=0;if(c<1){f=(v-c)/(1-c)}return[hsv[0],c*100,f*100]};convert.hcg.rgb=function(hcg){var h=hcg[0]/360;var c=hcg[1]/100;var g=hcg[2]/100;if(c===0){return[g*255,g*255,g*255]}var pure=[0,0,0];var hi=h%1*6;var v=hi%1;var w=1-v;var mg=0;switch(Math.floor(hi)){case 0:pure[0]=1;pure[1]=v;pure[2]=0;break;case 1:pure[0]=w;pure[1]=1;pure[2]=0;break;case 2:pure[0]=0;pure[1]=1;pure[2]=v;break;case 3:pure[0]=0;pure[1]=w;pure[2]=1;break;case 4:pure[0]=v;pure[1]=0;pure[2]=1;break;default:pure[0]=1;pure[1]=0;pure[2]=w}mg=(1-c)*g;return[(c*pure[0]+mg)*255,(c*pure[1]+mg)*255,(c*pure[2]+mg)*255]};convert.hcg.hsv=function(hcg){var c=hcg[1]/100;var g=hcg[2]/100;var v=c+g*(1-c);var f=0;if(v>0){f=c/v}return[hcg[0],f*100,v*100]};convert.hcg.hsl=function(hcg){var c=hcg[1]/100;var g=hcg[2]/100;var l=g*(1-c)+.5*c;var s=0;if(l>0&&l<.5){s=c/(2*l)}else if(l>=.5&&l<1){s=c/(2*(1-l))}return[hcg[0],s*100,l*100]};convert.hcg.hwb=function(hcg){var c=hcg[1]/100;var g=hcg[2]/100;var v=c+g*(1-c);return[hcg[0],(v-c)*100,(1-v)*100]};convert.hwb.hcg=function(hwb){var w=hwb[1]/100;var b=hwb[2]/100;var v=1-b;var c=v-w;var g=0;if(c<1){g=(v-c)/(1-c)}return[hwb[0],c*100,g*100]};convert.apple.rgb=function(apple){return[apple[0]/65535*255,apple[1]/65535*255,apple[2]/65535*255]};convert.rgb.apple=function(rgb){return[rgb[0]/255*65535,rgb[1]/255*65535,rgb[2]/255*65535]};convert.gray.rgb=function(args){return[args[0]/100*255,args[0]/100*255,args[0]/100*255]};convert.gray.hsl=convert.gray.hsv=function(args){return[0,0,args[0]]};convert.gray.hwb=function(gray){return[0,100,gray[0]]};convert.gray.cmyk=function(gray){return[0,0,0,gray[0]]};convert.gray.lab=function(gray){return[gray[0],0,0]};convert.gray.hex=function(gray){var val=Math.round(gray[0]/100*255)&255;var integer=(val<<16)+(val<<8)+val;var string=integer.toString(16).toUpperCase();return"000000".substring(string.length)+string};convert.rgb.gray=function(rgb){var val=(rgb[0]+rgb[1]+rgb[2])/3;return[val/255*100]}},function(module,exports,__webpack_require__){"use strict";var _typeof=typeof Symbol==="function"&&typeof Symbol.iterator==="symbol"?function(obj){return typeof obj}:function(obj){return obj&&typeof Symbol==="function"&&obj.constructor===Symbol&&obj!==Symbol.prototype?"symbol":typeof obj};var _Colorpicker=__webpack_require__(8);var _Colorpicker2=_interopRequireDefault(_Colorpicker);var _jquery=__webpack_require__(0);var _jquery2=_interopRequireDefault(_jquery);function _interopRequireDefault(obj){return obj&&obj.__esModule?obj:{default:obj}}var plugin="colorpicker";_jquery2.default[plugin]=_Colorpicker2.default;_jquery2.default.fn[plugin]=function(option){var fnArgs=Array.prototype.slice.call(arguments,1),isSingleElement=this.length===1,returnValue=null;var $elements=this.each(function(){var $this=(0,_jquery2.default)(this),inst=$this.data(plugin),options=(typeof option==="undefined"?"undefined":_typeof(option))==="object"?option:{};if(!inst){inst=new _Colorpicker2.default(this,options);$this.data(plugin,inst)}if(!isSingleElement){return}returnValue=$this;if(typeof option==="string"){if(option==="colorpicker"){returnValue=inst}else if(_jquery2.default.isFunction(inst[option])){returnValue=inst[option].apply(inst,fnArgs)}else{returnValue=inst[option]}}});return isSingleElement?returnValue:$elements};_jquery2.default.fn[plugin].constructor=_Colorpicker2.default},function(module,exports,__webpack_require__){"use strict";Object.defineProperty(exports,"__esModule",{value:true});var _createClass=function(){function defineProperties(target,props){for(var i=0;i1&&arguments[1]!==undefined?arguments[1]:{};var ext=new ExtensionClass(this,config);this.extensions.push(ext);return ext}},{key:"destroy",value:function destroy(){var color=this.color;this.sliderHandler.unbind();this.inputHandler.unbind();this.popupHandler.unbind();this.colorHandler.unbind();this.addonHandler.unbind();this.pickerHandler.unbind();this.element.removeClass("colorpicker-element").removeData("colorpicker","color").off(".colorpicker");this.trigger("colorpickerDestroy",color)}},{key:"show",value:function show(e){this.popupHandler.show(e)}},{key:"hide",value:function hide(e){this.popupHandler.hide(e)}},{key:"toggle",value:function toggle(e){this.popupHandler.toggle(e)}},{key:"getValue",value:function getValue(){var defaultValue=arguments.length>0&&arguments[0]!==undefined?arguments[0]:null;var val=this.colorHandler.color;val=val instanceof _ColorItem2.default?val:defaultValue;if(val instanceof _ColorItem2.default){return val.string(this.format)}return val}},{key:"setValue",value:function setValue(val){if(this.isDisabled()){return}var ch=this.colorHandler;if(ch.hasColor()&&!!val&&ch.color.equals(val)||!ch.hasColor()&&!val){return}ch.color=val?ch.createColor(val,this.options.autoInputFallback):null;this.trigger("colorpickerChange",ch.color,val);this.update()}},{key:"update",value:function update(){if(this.colorHandler.hasColor()){this.inputHandler.update()}else{this.colorHandler.assureColor()}this.addonHandler.update();this.pickerHandler.update();this.trigger("colorpickerUpdate")}},{key:"enable",value:function enable(){this.inputHandler.enable();this.disabled=false;this.picker.removeClass("colorpicker-disabled");this.trigger("colorpickerEnable");return true}},{key:"disable",value:function disable(){this.inputHandler.disable();this.disabled=true;this.picker.addClass("colorpicker-disabled");this.trigger("colorpickerDisable");return true}},{key:"isEnabled",value:function isEnabled(){return!this.isDisabled()}},{key:"isDisabled",value:function isDisabled(){return this.disabled===true}},{key:"trigger",value:function trigger(eventName){var color=arguments.length>1&&arguments[1]!==undefined?arguments[1]:null;var value=arguments.length>2&&arguments[2]!==undefined?arguments[2]:null;this.element.trigger({type:eventName,colorpicker:this,color:color?color:this.color,value:value?value:this.getValue()})}}]);return Colorpicker}();Colorpicker.extensions=_extensions2.default;exports.default=Colorpicker;module.exports=exports.default},function(module,exports,__webpack_require__){"use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.Palette=exports.Swatches=exports.Preview=exports.Debugger=undefined;var _Debugger=__webpack_require__(10);var _Debugger2=_interopRequireDefault(_Debugger);var _Preview=__webpack_require__(11);var _Preview2=_interopRequireDefault(_Preview);var _Swatches=__webpack_require__(12);var _Swatches2=_interopRequireDefault(_Swatches);var _Palette=__webpack_require__(4);var _Palette2=_interopRequireDefault(_Palette);function _interopRequireDefault(obj){return obj&&obj.__esModule?obj:{default:obj}}exports.Debugger=_Debugger2.default;exports.Preview=_Preview2.default;exports.Swatches=_Swatches2.default;exports.Palette=_Palette2.default;exports.default={debugger:_Debugger2.default,preview:_Preview2.default,swatches:_Swatches2.default,palette:_Palette2.default}},function(module,exports,__webpack_require__){"use strict";Object.defineProperty(exports,"__esModule",{value:true});var _createClass=function(){function defineProperties(target,props){for(var i=0;i1&&arguments[1]!==undefined?arguments[1]:{};_classCallCheck(this,Debugger);var _this=_possibleConstructorReturn(this,(Debugger.__proto__||Object.getPrototypeOf(Debugger)).call(this,colorpicker,options));_this.eventCounter=0;if(_this.colorpicker.inputHandler.hasInput()){_this.colorpicker.inputHandler.input.on("change.colorpicker-ext",_jquery2.default.proxy(_this.onChangeInput,_this))}return _this}_createClass(Debugger,[{key:"log",value:function log(eventName){var _console;for(var _len=arguments.length,args=Array(_len>1?_len-1:0),_key=1;_key<_len;_key++){args[_key-1]=arguments[_key]}this.eventCounter+=1;var logMessage="#"+this.eventCounter+": Colorpicker#"+this.colorpicker.id+" ["+eventName+"]";(_console=console).debug.apply(_console,[logMessage].concat(args));this.colorpicker.element.trigger({type:"colorpickerDebug",colorpicker:this.colorpicker,color:this.color,value:null,debug:{debugger:this,eventName,logArgs:args,logMessage}})}},{key:"resolveColor",value:function resolveColor(color){var realColor=arguments.length>1&&arguments[1]!==undefined?arguments[1]:true;this.log("resolveColor()",color,realColor);return false}},{key:"onCreate",value:function onCreate(event){this.log("colorpickerCreate");return _get(Debugger.prototype.__proto__||Object.getPrototypeOf(Debugger.prototype),"onCreate",this).call(this,event)}},{key:"onDestroy",value:function onDestroy(event){this.log("colorpickerDestroy");this.eventCounter=0;if(this.colorpicker.inputHandler.hasInput()){this.colorpicker.inputHandler.input.off(".colorpicker-ext")}return _get(Debugger.prototype.__proto__||Object.getPrototypeOf(Debugger.prototype),"onDestroy",this).call(this,event)}},{key:"onUpdate",value:function onUpdate(event){this.log("colorpickerUpdate")}},{key:"onChangeInput",value:function onChangeInput(event){this.log("input:change.colorpicker",event.value,event.color)}},{key:"onChange",value:function onChange(event){this.log("colorpickerChange",event.value,event.color)}},{key:"onInvalid",value:function onInvalid(event){this.log("colorpickerInvalid",event.value,event.color)}},{key:"onHide",value:function onHide(event){this.log("colorpickerHide");this.eventCounter=0}},{key:"onShow",value:function onShow(event){this.log("colorpickerShow")}},{key:"onDisable",value:function onDisable(event){this.log("colorpickerDisable")}},{key:"onEnable",value:function onEnable(event){this.log("colorpickerEnable")}}]);return Debugger}(_Extension3.default);exports.default=Debugger;module.exports=exports.default},function(module,exports,__webpack_require__){"use strict";Object.defineProperty(exports,"__esModule",{value:true});var _createClass=function(){function defineProperties(target,props){for(var i=0;i1&&arguments[1]!==undefined?arguments[1]:{};_classCallCheck(this,Preview);var _this=_possibleConstructorReturn(this,(Preview.__proto__||Object.getPrototypeOf(Preview)).call(this,colorpicker,_jquery2.default.extend(true,{},{template:'
',showText:true,format:colorpicker.format},options)));_this.element=(0,_jquery2.default)(_this.options.template);_this.elementInner=_this.element.find("div");return _this}_createClass(Preview,[{key:"onCreate",value:function onCreate(event){_get(Preview.prototype.__proto__||Object.getPrototypeOf(Preview.prototype),"onCreate",this).call(this,event);this.colorpicker.picker.append(this.element)}},{key:"onUpdate",value:function onUpdate(event){_get(Preview.prototype.__proto__||Object.getPrototypeOf(Preview.prototype),"onUpdate",this).call(this,event);if(!event.color){this.elementInner.css("backgroundColor",null).css("color",null).html("");return}this.elementInner.css("backgroundColor",event.color.toRgbString());if(this.options.showText){this.elementInner.html(event.color.string(this.options.format||this.colorpicker.format));if(event.color.isDark()&&event.color.alpha>.5){this.elementInner.css("color","white")}else{this.elementInner.css("color","black")}}}}]);return Preview}(_Extension3.default);exports.default=Preview;module.exports=exports.default},function(module,exports,__webpack_require__){"use strict";Object.defineProperty(exports,"__esModule",{value:true});var _createClass=function(){function defineProperties(target,props){for(var i=0;i\n
\n
',swatchTemplate:''};var Swatches=function(_Palette){_inherits(Swatches,_Palette);function Swatches(colorpicker){var options=arguments.length>1&&arguments[1]!==undefined?arguments[1]:{};_classCallCheck(this,Swatches);var _this=_possibleConstructorReturn(this,(Swatches.__proto__||Object.getPrototypeOf(Swatches)).call(this,colorpicker,_jquery2.default.extend(true,{},defaults,options)));_this.element=null;return _this}_createClass(Swatches,[{key:"isEnabled",value:function isEnabled(){return this.getLength()>0}},{key:"onCreate",value:function onCreate(event){_get(Swatches.prototype.__proto__||Object.getPrototypeOf(Swatches.prototype),"onCreate",this).call(this,event);if(!this.isEnabled()){return}this.element=(0,_jquery2.default)(this.options.barTemplate);this.load();this.colorpicker.picker.append(this.element)}},{key:"load",value:function load(){var _this2=this;var colorpicker=this.colorpicker,swatchContainer=this.element.find(".colorpicker-swatches--inner"),isAliased=this.options.namesAsValues===true&&!Array.isArray(this.colors);swatchContainer.empty();_jquery2.default.each(this.colors,function(name,value){var $swatch=(0,_jquery2.default)(_this2.options.swatchTemplate).attr("data-name",name).attr("data-value",value).attr("title",isAliased?name+": "+value:value).on("mousedown.colorpicker touchstart.colorpicker",function(e){var $sw=(0,_jquery2.default)(this);colorpicker.setValue(isAliased?$sw.attr("data-name"):$sw.attr("data-value"))});$swatch.find(".colorpicker-swatch--inner").css("background-color",value);swatchContainer.append($swatch)});swatchContainer.append((0,_jquery2.default)(''))}}]);return Swatches}(_Palette3.default);exports.default=Swatches;module.exports=exports.default},function(module,exports,__webpack_require__){"use strict";Object.defineProperty(exports,"__esModule",{value:true});var _createClass=function(){function defineProperties(target,props){for(var i=0;i0}},{key:"onClickingInside",value:function onClickingInside(e){this.clicking=this.isClickingInside(e)}},{key:"createPopover",value:function createPopover(){var cp=this.colorpicker;this.popoverTarget=this.hasAddon?this.addon:this.input;cp.picker.addClass("colorpicker-bs-popover-content");this.popoverTarget.popover(_jquery2.default.extend(true,{},_options2.default.popover,cp.options.popover,{trigger:"manual",content:cp.picker,html:true}));this.popoverTip=(0,_jquery2.default)(this.popoverTarget.popover("getTipElement").data("bs.popover").tip);this.popoverTip.addClass("colorpicker-bs-popover");this.popoverTarget.on("shown.bs.popover",_jquery2.default.proxy(this.fireShow,this));this.popoverTarget.on("hidden.bs.popover",_jquery2.default.proxy(this.fireHide,this))}},{key:"reposition",value:function reposition(e){if(this.popoverTarget&&this.isVisible()){this.popoverTarget.popover("update")}}},{key:"toggle",value:function toggle(e){if(this.isVisible()){this.hide(e)}else{this.show(e)}}},{key:"show",value:function show(e){if(this.isVisible()||this.showing||this.hidding){return}this.showing=true;this.hidding=false;this.clicking=false;var cp=this.colorpicker;cp.lastEvent.alias="show";cp.lastEvent.e=e;if(e&&(!this.hasInput||this.input.attr("type")==="color")&&e&&e.preventDefault){e.stopPropagation();e.preventDefault()}if(this.isPopover){(0,_jquery2.default)(this.root).on("resize.colorpicker",_jquery2.default.proxy(this.reposition,this))}cp.picker.addClass("colorpicker-visible").removeClass("colorpicker-hidden");if(this.popoverTarget){this.popoverTarget.popover("show")}else{this.fireShow()}}},{key:"fireShow",value:function fireShow(){this.hidding=false;this.showing=false;if(this.isPopover){(0,_jquery2.default)(this.root.document).on("mousedown.colorpicker touchstart.colorpicker",_jquery2.default.proxy(this.hide,this));(0,_jquery2.default)(this.root.document).on("mousedown.colorpicker touchstart.colorpicker",_jquery2.default.proxy(this.onClickingInside,this))}this.colorpicker.trigger("colorpickerShow")}},{key:"hide",value:function hide(e){if(this.isHidden()||this.showing||this.hidding){return}var cp=this.colorpicker,clicking=this.clicking||this.isClickingInside(e);this.hidding=true;this.showing=false;this.clicking=false;cp.lastEvent.alias="hide";cp.lastEvent.e=e;if(clicking){this.hidding=false;return}if(this.popoverTarget){this.popoverTarget.popover("hide")}else{this.fireHide()}}},{key:"fireHide",value:function fireHide(){this.hidding=false;this.showing=false;var cp=this.colorpicker;cp.picker.addClass("colorpicker-hidden").removeClass("colorpicker-visible");(0,_jquery2.default)(this.root).off("resize.colorpicker",_jquery2.default.proxy(this.reposition,this));(0,_jquery2.default)(this.root.document).off("mousedown.colorpicker touchstart.colorpicker",_jquery2.default.proxy(this.hide,this));(0,_jquery2.default)(this.root.document).off("mousedown.colorpicker touchstart.colorpicker",_jquery2.default.proxy(this.onClickingInside,this));cp.trigger("colorpickerHide")}},{key:"focus",value:function focus(){if(this.hasAddon){return this.addon.focus()}if(this.hasInput){return this.input.focus()}return false}},{key:"isVisible",value:function isVisible(){return this.colorpicker.picker.hasClass("colorpicker-visible")&&!this.colorpicker.picker.hasClass("colorpicker-hidden")}},{key:"isHidden",value:function isHidden(){return this.colorpicker.picker.hasClass("colorpicker-hidden")&&!this.colorpicker.picker.hasClass("colorpicker-visible")}},{key:"input",get:function get(){return this.colorpicker.inputHandler.input}},{key:"hasInput",get:function get(){return this.colorpicker.inputHandler.hasInput()}},{key:"addon",get:function get(){return this.colorpicker.addonHandler.addon}},{key:"hasAddon",get:function get(){return this.colorpicker.addonHandler.hasAddon()}},{key:"isPopover",get:function get(){return!this.colorpicker.options.inline&&!!this.popoverTip}}]);return PopupHandler}();exports.default=PopupHandler;module.exports=exports.default},function(module,exports,__webpack_require__){"use strict";Object.defineProperty(exports,"__esModule",{value:true});var _createClass=function(){function defineProperties(target,props){for(var i=0;i0&&arguments[0]!==undefined?arguments[0]:null;val=val?val:this.colorpicker.colorHandler.getColorString();if(!val){return""}val=this.colorpicker.colorHandler.resolveColorDelegate(val,false);if(this.colorpicker.options.useHashPrefix===false){val=val.replace(/^#/g,"")}return val}},{key:"hasInput",value:function hasInput(){return this.input!==false}},{key:"isEnabled",value:function isEnabled(){return this.hasInput()&&!this.isDisabled()}},{key:"isDisabled",value:function isDisabled(){return this.hasInput()&&this.input.prop("disabled")===true}},{key:"disable",value:function disable(){if(this.hasInput()){this.input.prop("disabled",true)}}},{key:"enable",value:function enable(){if(this.hasInput()){this.input.prop("disabled",false)}}},{key:"update",value:function update(){if(!this.hasInput()){return}if(this.colorpicker.options.autoInputFallback===false&&this.colorpicker.colorHandler.isInvalidColor()){return}this.setValue(this.getFormattedColor())}},{key:"onchange",value:function onchange(e){this.colorpicker.lastEvent.alias="input.change";this.colorpicker.lastEvent.e=e;var val=this.getValue();if(val!==e.value){this.colorpicker.setValue(val)}}},{key:"onkeyup",value:function onkeyup(e){this.colorpicker.lastEvent.alias="input.keyup";this.colorpicker.lastEvent.e=e;var val=this.getValue();if(val!==e.value){this.colorpicker.setValue(val)}}}]);return InputHandler}();exports.default=InputHandler;module.exports=exports.default},function(module,exports,__webpack_require__){"use strict";var colorString=__webpack_require__(17);var convert=__webpack_require__(20);var _slice=[].slice;var skippedModels=["keyword","gray","hex"];var hashedModelKeys={};Object.keys(convert).forEach(function(model){hashedModelKeys[_slice.call(convert[model].labels).sort().join("")]=model});var limiters={};function Color(obj,model){if(!(this instanceof Color)){return new Color(obj,model)}if(model&&model in skippedModels){model=null}if(model&&!(model in convert)){throw new Error("Unknown model: "+model)}var i;var channels;if(obj==null){this.model="rgb";this.color=[0,0,0];this.valpha=1}else if(obj instanceof Color){this.model=obj.model;this.color=obj.color.slice();this.valpha=obj.valpha}else if(typeof obj==="string"){var result=colorString.get(obj);if(result===null){throw new Error("Unable to parse color from string: "+obj)}this.model=result.model;channels=convert[this.model].channels;this.color=result.value.slice(0,channels);this.valpha=typeof result.value[channels]==="number"?result.value[channels]:1}else if(obj.length){this.model=model||"rgb";channels=convert[this.model].channels;var newArr=_slice.call(obj,0,channels);this.color=zeroArray(newArr,channels);this.valpha=typeof obj[channels]==="number"?obj[channels]:1}else if(typeof obj==="number"){obj&=16777215;this.model="rgb";this.color=[obj>>16&255,obj>>8&255,obj&255];this.valpha=1}else{this.valpha=1;var keys=Object.keys(obj);if("alpha"in obj){keys.splice(keys.indexOf("alpha"),1);this.valpha=typeof obj.alpha==="number"?obj.alpha:0}var hashedKeys=keys.sort().join("");if(!(hashedKeys in hashedModelKeys)){throw new Error("Unable to parse color from object: "+JSON.stringify(obj))}this.model=hashedModelKeys[hashedKeys];var labels=convert[this.model].labels;var color=[];for(i=0;ilum2){return(lum1+.05)/(lum2+.05)}return(lum2+.05)/(lum1+.05)},level:function(color2){var contrastRatio=this.contrast(color2);if(contrastRatio>=7.1){return"AAA"}return contrastRatio>=4.5?"AA":""},isDark:function(){var rgb=this.rgb().color;var yiq=(rgb[0]*299+rgb[1]*587+rgb[2]*114)/1e3;return yiq<128},isLight:function(){return!this.isDark()},negate:function(){var rgb=this.rgb();for(var i=0;i<3;i++){rgb.color[i]=255-rgb.color[i]}return rgb},lighten:function(ratio){var hsl=this.hsl();hsl.color[2]+=hsl.color[2]*ratio;return hsl},darken:function(ratio){var hsl=this.hsl();hsl.color[2]-=hsl.color[2]*ratio;return hsl},saturate:function(ratio){var hsl=this.hsl();hsl.color[1]+=hsl.color[1]*ratio;return hsl},desaturate:function(ratio){var hsl=this.hsl();hsl.color[1]-=hsl.color[1]*ratio;return hsl},whiten:function(ratio){var hwb=this.hwb();hwb.color[1]+=hwb.color[1]*ratio;return hwb},blacken:function(ratio){var hwb=this.hwb();hwb.color[2]+=hwb.color[2]*ratio;return hwb},grayscale:function(){var rgb=this.rgb().color;var val=rgb[0]*.3+rgb[1]*.59+rgb[2]*.11;return Color.rgb(val,val,val)},fade:function(ratio){return this.alpha(this.valpha-this.valpha*ratio)},opaquer:function(ratio){return this.alpha(this.valpha+this.valpha*ratio)},rotate:function(degrees){var hsl=this.hsl();var hue=hsl.color[0];hue=(hue+degrees)%360;hue=hue<0?360+hue:hue;hsl.color[0]=hue;return hsl},mix:function(mixinColor,weight){if(!mixinColor||!mixinColor.rgb){throw new Error('Argument to "mix" was not a Color instance, but rather an instance of '+typeof mixinColor)}var color1=mixinColor.rgb();var color2=this.rgb();var p=weight===undefined?.5:weight;var w=2*p-1;var a=color1.alpha()-color2.alpha();var w1=((w*a===-1?w:(w+a)/(1+w*a))+1)/2;var w2=1-w1;return Color.rgb(w1*color1.red()+w2*color2.red(),w1*color1.green()+w2*color2.green(),w1*color1.blue()+w2*color2.blue(),color1.alpha()*p+color2.alpha()*(1-p))}};Object.keys(convert).forEach(function(model){if(skippedModels.indexOf(model)!==-1){return}var channels=convert[model].channels;Color.prototype[model]=function(){if(this.model===model){return new Color(this)}if(arguments.length){return new Color(arguments,model)}var newAlpha=typeof arguments[channels]==="number"?channels:this.valpha;return new Color(assertArray(convert[this.model][model].raw(this.color)).concat(newAlpha),model)};Color[model]=function(color){if(typeof color==="number"){color=zeroArray(_slice.call(arguments),channels)}return new Color(color,model)}});function roundTo(num,places){return Number(num.toFixed(places))}function roundToPlace(places){return function(num){return roundTo(num,places)}}function getset(model,channel,modifier){model=Array.isArray(model)?model:[model];model.forEach(function(m){(limiters[m]||(limiters[m]=[]))[channel]=modifier});model=model[0];return function(val){var result;if(arguments.length){if(modifier){val=modifier(val)}result=this[model]();result.color[channel]=val;return result}result=this[model]().color[channel];if(modifier){result=modifier(result)}return result}}function maxfn(max){return function(v){return Math.max(0,Math.min(max,v))}}function assertArray(val){return Array.isArray(val)?val:[val]}function zeroArray(arr,length){for(var i=0;i=4&&hwba[3]!==1){a=", "+hwba[3]}return"hwb("+hwba[0]+", "+hwba[1]+"%, "+hwba[2]+"%"+a+")"};cs.to.keyword=function(rgb){return reverseNames[rgb.slice(0,3)]};function clamp(num,min,max){return Math.min(Math.max(min,num),max)}function hexDouble(num){var str=num.toString(16).toUpperCase();return str.length<2?"0"+str:str}},function(module,exports,__webpack_require__){"use strict";var isArrayish=__webpack_require__(19);var concat=Array.prototype.concat;var slice=Array.prototype.slice;var swizzle=module.exports=function swizzle(args){var results=[];for(var i=0,len=args.length;i=0&&obj.splice instanceof Function}},function(module,exports,__webpack_require__){var conversions=__webpack_require__(6);var route=__webpack_require__(21);var convert={};var models=Object.keys(conversions);function wrapRaw(fn){var wrappedFn=function(args){if(args===undefined||args===null){return args}if(arguments.length>1){args=Array.prototype.slice.call(arguments)}return fn(args)};if("conversion"in fn){wrappedFn.conversion=fn.conversion}return wrappedFn}function wrapRounded(fn){var wrappedFn=function(args){if(args===undefined||args===null){return args}if(arguments.length>1){args=Array.prototype.slice.call(arguments)}var result=fn(args);if(typeof result==="object"){for(var len=result.length,i=0;i1&&arguments[1]!==undefined?arguments[1]:true;var color=new _ColorItem2.default(this.resolveColorDelegate(val),this.format);if(!color.isValid()){if(fallbackOnInvalid){color=this.getFallbackColor()}this.colorpicker.trigger("colorpickerInvalid",color,val)}if(!this.isAlphaEnabled()){color.alpha=1}return color}},{key:"getFallbackColor",value:function getFallbackColor(){if(this.fallback&&this.fallback===this.color){return this.color}var fallback=this.resolveColorDelegate(this.fallback);var color=new _ColorItem2.default(fallback,this.format);if(!color.isValid()){console.warn("The fallback color is invalid. Falling back to the previous color or black if any.");return this.color?this.color:new _ColorItem2.default("#000000",this.format)}return color}},{key:"assureColor",value:function assureColor(){if(!this.hasColor()){this.color=this.getFallbackColor()}return this.color}},{key:"resolveColorDelegate",value:function resolveColorDelegate(color){var realColor=arguments.length>1&&arguments[1]!==undefined?arguments[1]:true;var extResolvedColor=false;_jquery2.default.each(this.colorpicker.extensions,function(name,ext){if(extResolvedColor!==false){return}extResolvedColor=ext.resolveColor(color,realColor)});return extResolvedColor?extResolvedColor:color}},{key:"isInvalidColor",value:function isInvalidColor(){return!this.hasColor()||!this.color.isValid()}},{key:"isAlphaEnabled",value:function isAlphaEnabled(){return this.colorpicker.options.useAlpha!==false}},{key:"hasColor",value:function hasColor(){return this.color instanceof _ColorItem2.default}},{key:"fallback",get:function get(){return this.colorpicker.options.fallbackColor?this.colorpicker.options.fallbackColor:this.hasColor()?this.color:null}},{key:"format",get:function get(){if(this.colorpicker.options.format){return this.colorpicker.options.format}if(this.hasColor()&&this.color.hasTransparency()&&this.color.format.match(/^hex/)){return this.isAlphaEnabled()?"rgba":"hex"}if(this.hasColor()){return this.color.format}return"rgb"}},{key:"color",get:function get(){return this.colorpicker.element.data("color")},set:function set(value){this.colorpicker.element.data("color",value);if(value instanceof _ColorItem2.default&&this.colorpicker.options.format==="auto"){this.colorpicker.options.format=this.color.format}}}]);return ColorHandler}();exports.default=ColorHandler;module.exports=exports.default},function(module,exports,__webpack_require__){"use strict";Object.defineProperty(exports,"__esModule",{value:true});var _createClass=function(){function defineProperties(target,props){for(var i=0;i0){icn.css(styles)}else{this.addon.css(styles)}}}]);return AddonHandler}();exports.default=AddonHandler;module.exports=exports.default}])}); +//# sourceMappingURL=bootstrap-colorpicker.min.js.map \ No newline at end of file diff --git a/hal-core/resources/web/js/lib/bootstrap-switch.LICENSE b/hal-core/resources/web/js/lib/bootstrap-switch.LICENSE new file mode 100644 index 00000000..31e23cd1 --- /dev/null +++ b/hal-core/resources/web/js/lib/bootstrap-switch.LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2013-2015 The authors of Bootstrap Switch + +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. diff --git a/hal-core/resources/web/js/lib/bootstrap-switch.LICENSE.txt b/hal-core/resources/web/js/lib/bootstrap-switch.LICENSE.txt new file mode 100644 index 00000000..31e23cd1 --- /dev/null +++ b/hal-core/resources/web/js/lib/bootstrap-switch.LICENSE.txt @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2013-2015 The authors of Bootstrap Switch + +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. diff --git a/hal-core/resources/web/js/lib/bootstrap-switch.js b/hal-core/resources/web/js/lib/bootstrap-switch.js new file mode 100644 index 00000000..511f08fa --- /dev/null +++ b/hal-core/resources/web/js/lib/bootstrap-switch.js @@ -0,0 +1,784 @@ +/** + * bootstrap-switch - Turn checkboxes and radio buttons into toggle switches. + * + * @version v3.3.4 + * @homepage https://bttstrp.github.io/bootstrap-switch + * @author Mattia Larentis (http://larentis.eu) + * @license Apache-2.0 + */ + +(function (global, factory) { + if (typeof define === "function" && define.amd) { + define(['jquery'], factory); + } else if (typeof exports !== "undefined") { + factory(require('jquery')); + } else { + var mod = { + exports: {} + }; + factory(global.jquery); + global.bootstrapSwitch = mod.exports; + } +})(this, function (_jquery) { + 'use strict'; + + var _jquery2 = _interopRequireDefault(_jquery); + + function _interopRequireDefault(obj) { + return obj && obj.__esModule ? obj : { + default: obj + }; + } + + var _extends = Object.assign || function (target) { + for (var i = 1; i < arguments.length; i++) { + var source = arguments[i]; + + for (var key in source) { + if (Object.prototype.hasOwnProperty.call(source, key)) { + target[key] = source[key]; + } + } + } + + return target; + }; + + function _classCallCheck(instance, Constructor) { + if (!(instance instanceof Constructor)) { + throw new TypeError("Cannot call a class as a function"); + } + } + + var _createClass = function () { + function defineProperties(target, props) { + for (var i = 0; i < props.length; i++) { + var descriptor = props[i]; + descriptor.enumerable = descriptor.enumerable || false; + descriptor.configurable = true; + if ("value" in descriptor) descriptor.writable = true; + Object.defineProperty(target, descriptor.key, descriptor); + } + } + + return function (Constructor, protoProps, staticProps) { + if (protoProps) defineProperties(Constructor.prototype, protoProps); + if (staticProps) defineProperties(Constructor, staticProps); + return Constructor; + }; + }(); + + var $ = _jquery2.default || window.jQuery || window.$; + + var BootstrapSwitch = function () { + function BootstrapSwitch(element) { + var _this = this; + + var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; + + _classCallCheck(this, BootstrapSwitch); + + this.$element = $(element); + this.options = $.extend({}, $.fn.bootstrapSwitch.defaults, this._getElementOptions(), options); + this.prevOptions = {}; + this.$wrapper = $('
', { + class: function _class() { + var classes = []; + classes.push(_this.options.state ? 'on' : 'off'); + if (_this.options.size) { + classes.push(_this.options.size); + } + if (_this.options.disabled) { + classes.push('disabled'); + } + if (_this.options.readonly) { + classes.push('readonly'); + } + if (_this.options.indeterminate) { + classes.push('indeterminate'); + } + if (_this.options.inverse) { + classes.push('inverse'); + } + if (_this.$element.attr('id')) { + classes.push('id-' + _this.$element.attr('id')); + } + return classes.map(_this._getClass.bind(_this)).concat([_this.options.baseClass], _this._getClasses(_this.options.wrapperClass)).join(' '); + } + }); + this.$container = $('
', { class: this._getClass('container') }); + this.$on = $('', { + html: this.options.onText, + class: this._getClass('handle-on') + ' ' + this._getClass(this.options.onColor) + }); + this.$off = $('', { + html: this.options.offText, + class: this._getClass('handle-off') + ' ' + this._getClass(this.options.offColor) + }); + this.$label = $('', { + html: this.options.labelText, + class: this._getClass('label') + }); + + this.$element.on('init.bootstrapSwitch', this.options.onInit.bind(this, element)); + this.$element.on('switchChange.bootstrapSwitch', function () { + for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) { + args[_key] = arguments[_key]; + } + + if (_this.options.onSwitchChange.apply(element, args) === false) { + if (_this.$element.is(':radio')) { + $('[name="' + _this.$element.attr('name') + '"]').trigger('previousState.bootstrapSwitch', true); + } else { + _this.$element.trigger('previousState.bootstrapSwitch', true); + } + } + }); + + this.$container = this.$element.wrap(this.$container).parent(); + this.$wrapper = this.$container.wrap(this.$wrapper).parent(); + this.$element.before(this.options.inverse ? this.$off : this.$on).before(this.$label).before(this.options.inverse ? this.$on : this.$off); + + if (this.options.indeterminate) { + this.$element.prop('indeterminate', true); + } + + this._init(); + this._elementHandlers(); + this._handleHandlers(); + this._labelHandlers(); + this._formHandler(); + this._externalLabelHandler(); + this.$element.trigger('init.bootstrapSwitch', this.options.state); + } + + _createClass(BootstrapSwitch, [{ + key: 'setPrevOptions', + value: function setPrevOptions() { + this.prevOptions = _extends({}, this.options); + } + }, { + key: 'state', + value: function state(value, skip) { + if (typeof value === 'undefined') { + return this.options.state; + } + if (this.options.disabled || this.options.readonly || this.options.state && !this.options.radioAllOff && this.$element.is(':radio')) { + return this.$element; + } + if (this.$element.is(':radio')) { + $('[name="' + this.$element.attr('name') + '"]').trigger('setPreviousOptions.bootstrapSwitch'); + } else { + this.$element.trigger('setPreviousOptions.bootstrapSwitch'); + } + if (this.options.indeterminate) { + this.indeterminate(false); + } + this.$element.prop('checked', Boolean(value)).trigger('change.bootstrapSwitch', skip); + return this.$element; + } + }, { + key: 'toggleState', + value: function toggleState(skip) { + if (this.options.disabled || this.options.readonly) { + return this.$element; + } + if (this.options.indeterminate) { + this.indeterminate(false); + return this.state(true); + } else { + return this.$element.prop('checked', !this.options.state).trigger('change.bootstrapSwitch', skip); + } + } + }, { + key: 'size', + value: function size(value) { + if (typeof value === 'undefined') { + return this.options.size; + } + if (this.options.size != null) { + this.$wrapper.removeClass(this._getClass(this.options.size)); + } + if (value) { + this.$wrapper.addClass(this._getClass(value)); + } + this._width(); + this._containerPosition(); + this.options.size = value; + return this.$element; + } + }, { + key: 'animate', + value: function animate(value) { + if (typeof value === 'undefined') { + return this.options.animate; + } + if (this.options.animate === Boolean(value)) { + return this.$element; + } + return this.toggleAnimate(); + } + }, { + key: 'toggleAnimate', + value: function toggleAnimate() { + this.options.animate = !this.options.animate; + this.$wrapper.toggleClass(this._getClass('animate')); + return this.$element; + } + }, { + key: 'disabled', + value: function disabled(value) { + if (typeof value === 'undefined') { + return this.options.disabled; + } + if (this.options.disabled === Boolean(value)) { + return this.$element; + } + return this.toggleDisabled(); + } + }, { + key: 'toggleDisabled', + value: function toggleDisabled() { + this.options.disabled = !this.options.disabled; + this.$element.prop('disabled', this.options.disabled); + this.$wrapper.toggleClass(this._getClass('disabled')); + return this.$element; + } + }, { + key: 'readonly', + value: function readonly(value) { + if (typeof value === 'undefined') { + return this.options.readonly; + } + if (this.options.readonly === Boolean(value)) { + return this.$element; + } + return this.toggleReadonly(); + } + }, { + key: 'toggleReadonly', + value: function toggleReadonly() { + this.options.readonly = !this.options.readonly; + this.$element.prop('readonly', this.options.readonly); + this.$wrapper.toggleClass(this._getClass('readonly')); + return this.$element; + } + }, { + key: 'indeterminate', + value: function indeterminate(value) { + if (typeof value === 'undefined') { + return this.options.indeterminate; + } + if (this.options.indeterminate === Boolean(value)) { + return this.$element; + } + return this.toggleIndeterminate(); + } + }, { + key: 'toggleIndeterminate', + value: function toggleIndeterminate() { + this.options.indeterminate = !this.options.indeterminate; + this.$element.prop('indeterminate', this.options.indeterminate); + this.$wrapper.toggleClass(this._getClass('indeterminate')); + this._containerPosition(); + return this.$element; + } + }, { + key: 'inverse', + value: function inverse(value) { + if (typeof value === 'undefined') { + return this.options.inverse; + } + if (this.options.inverse === Boolean(value)) { + return this.$element; + } + return this.toggleInverse(); + } + }, { + key: 'toggleInverse', + value: function toggleInverse() { + this.$wrapper.toggleClass(this._getClass('inverse')); + var $on = this.$on.clone(true); + var $off = this.$off.clone(true); + this.$on.replaceWith($off); + this.$off.replaceWith($on); + this.$on = $off; + this.$off = $on; + this.options.inverse = !this.options.inverse; + return this.$element; + } + }, { + key: 'onColor', + value: function onColor(value) { + if (typeof value === 'undefined') { + return this.options.onColor; + } + if (this.options.onColor) { + this.$on.removeClass(this._getClass(this.options.onColor)); + } + this.$on.addClass(this._getClass(value)); + this.options.onColor = value; + return this.$element; + } + }, { + key: 'offColor', + value: function offColor(value) { + if (typeof value === 'undefined') { + return this.options.offColor; + } + if (this.options.offColor) { + this.$off.removeClass(this._getClass(this.options.offColor)); + } + this.$off.addClass(this._getClass(value)); + this.options.offColor = value; + return this.$element; + } + }, { + key: 'onText', + value: function onText(value) { + if (typeof value === 'undefined') { + return this.options.onText; + } + this.$on.html(value); + this._width(); + this._containerPosition(); + this.options.onText = value; + return this.$element; + } + }, { + key: 'offText', + value: function offText(value) { + if (typeof value === 'undefined') { + return this.options.offText; + } + this.$off.html(value); + this._width(); + this._containerPosition(); + this.options.offText = value; + return this.$element; + } + }, { + key: 'labelText', + value: function labelText(value) { + if (typeof value === 'undefined') { + return this.options.labelText; + } + this.$label.html(value); + this._width(); + this.options.labelText = value; + return this.$element; + } + }, { + key: 'handleWidth', + value: function handleWidth(value) { + if (typeof value === 'undefined') { + return this.options.handleWidth; + } + this.options.handleWidth = value; + this._width(); + this._containerPosition(); + return this.$element; + } + }, { + key: 'labelWidth', + value: function labelWidth(value) { + if (typeof value === 'undefined') { + return this.options.labelWidth; + } + this.options.labelWidth = value; + this._width(); + this._containerPosition(); + return this.$element; + } + }, { + key: 'baseClass', + value: function baseClass(value) { + return this.options.baseClass; + } + }, { + key: 'wrapperClass', + value: function wrapperClass(value) { + if (typeof value === 'undefined') { + return this.options.wrapperClass; + } + if (!value) { + value = $.fn.bootstrapSwitch.defaults.wrapperClass; + } + this.$wrapper.removeClass(this._getClasses(this.options.wrapperClass).join(' ')); + this.$wrapper.addClass(this._getClasses(value).join(' ')); + this.options.wrapperClass = value; + return this.$element; + } + }, { + key: 'radioAllOff', + value: function radioAllOff(value) { + if (typeof value === 'undefined') { + return this.options.radioAllOff; + } + var val = Boolean(value); + if (this.options.radioAllOff === val) { + return this.$element; + } + this.options.radioAllOff = val; + return this.$element; + } + }, { + key: 'onInit', + value: function onInit(value) { + if (typeof value === 'undefined') { + return this.options.onInit; + } + if (!value) { + value = $.fn.bootstrapSwitch.defaults.onInit; + } + this.options.onInit = value; + return this.$element; + } + }, { + key: 'onSwitchChange', + value: function onSwitchChange(value) { + if (typeof value === 'undefined') { + return this.options.onSwitchChange; + } + if (!value) { + value = $.fn.bootstrapSwitch.defaults.onSwitchChange; + } + this.options.onSwitchChange = value; + return this.$element; + } + }, { + key: 'destroy', + value: function destroy() { + var $form = this.$element.closest('form'); + if ($form.length) { + $form.off('reset.bootstrapSwitch').removeData('bootstrap-switch'); + } + this.$container.children().not(this.$element).remove(); + this.$element.unwrap().unwrap().off('.bootstrapSwitch').removeData('bootstrap-switch'); + return this.$element; + } + }, { + key: '_getElementOptions', + value: function _getElementOptions() { + return { + state: this.$element.is(':checked'), + size: this.$element.data('size'), + animate: this.$element.data('animate'), + disabled: this.$element.is(':disabled'), + readonly: this.$element.is('[readonly]'), + indeterminate: this.$element.data('indeterminate'), + inverse: this.$element.data('inverse'), + radioAllOff: this.$element.data('radio-all-off'), + onColor: this.$element.data('on-color'), + offColor: this.$element.data('off-color'), + onText: this.$element.data('on-text'), + offText: this.$element.data('off-text'), + labelText: this.$element.data('label-text'), + handleWidth: this.$element.data('handle-width'), + labelWidth: this.$element.data('label-width'), + baseClass: this.$element.data('base-class'), + wrapperClass: this.$element.data('wrapper-class') + }; + } + }, { + key: '_width', + value: function _width() { + var _this2 = this; + + var $handles = this.$on.add(this.$off).add(this.$label).css('width', ''); + var handleWidth = this.options.handleWidth === 'auto' ? Math.round(Math.max(this.$on.width(), this.$off.width())) : this.options.handleWidth; + $handles.width(handleWidth); + this.$label.width(function (index, width) { + if (_this2.options.labelWidth !== 'auto') { + return _this2.options.labelWidth; + } + if (width < handleWidth) { + return handleWidth; + } + return width; + }); + this._handleWidth = this.$on.outerWidth(); + this._labelWidth = this.$label.outerWidth(); + this.$container.width(this._handleWidth * 2 + this._labelWidth); + return this.$wrapper.width(this._handleWidth + this._labelWidth); + } + }, { + key: '_containerPosition', + value: function _containerPosition() { + var _this3 = this; + + var state = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : this.options.state; + var callback = arguments[1]; + + this.$container.css('margin-left', function () { + var values = [0, '-' + _this3._handleWidth + 'px']; + if (_this3.options.indeterminate) { + return '-' + _this3._handleWidth / 2 + 'px'; + } + if (state) { + if (_this3.options.inverse) { + return values[1]; + } else { + return values[0]; + } + } else { + if (_this3.options.inverse) { + return values[0]; + } else { + return values[1]; + } + } + }); + } + }, { + key: '_init', + value: function _init() { + var _this4 = this; + + var init = function init() { + _this4.setPrevOptions(); + _this4._width(); + _this4._containerPosition(); + setTimeout(function () { + if (_this4.options.animate) { + return _this4.$wrapper.addClass(_this4._getClass('animate')); + } + }, 50); + }; + if (this.$wrapper.is(':visible')) { + init(); + return; + } + var initInterval = window.setInterval(function () { + if (_this4.$wrapper.is(':visible')) { + init(); + return window.clearInterval(initInterval); + } + }, 50); + } + }, { + key: '_elementHandlers', + value: function _elementHandlers() { + var _this5 = this; + + return this.$element.on({ + 'setPreviousOptions.bootstrapSwitch': this.setPrevOptions.bind(this), + + 'previousState.bootstrapSwitch': function previousStateBootstrapSwitch() { + _this5.options = _this5.prevOptions; + if (_this5.options.indeterminate) { + _this5.$wrapper.addClass(_this5._getClass('indeterminate')); + } + _this5.$element.prop('checked', _this5.options.state).trigger('change.bootstrapSwitch', true); + }, + + 'change.bootstrapSwitch': function changeBootstrapSwitch(event, skip) { + event.preventDefault(); + event.stopImmediatePropagation(); + var state = _this5.$element.is(':checked'); + _this5._containerPosition(state); + if (state === _this5.options.state) { + return; + } + _this5.options.state = state; + _this5.$wrapper.toggleClass(_this5._getClass('off')).toggleClass(_this5._getClass('on')); + if (!skip) { + if (_this5.$element.is(':radio')) { + $('[name="' + _this5.$element.attr('name') + '"]').not(_this5.$element).prop('checked', false).trigger('change.bootstrapSwitch', true); + } + _this5.$element.trigger('switchChange.bootstrapSwitch', [state]); + } + }, + + 'focus.bootstrapSwitch': function focusBootstrapSwitch(event) { + event.preventDefault(); + _this5.$wrapper.addClass(_this5._getClass('focused')); + }, + + 'blur.bootstrapSwitch': function blurBootstrapSwitch(event) { + event.preventDefault(); + _this5.$wrapper.removeClass(_this5._getClass('focused')); + }, + + 'keydown.bootstrapSwitch': function keydownBootstrapSwitch(event) { + if (!event.which || _this5.options.disabled || _this5.options.readonly) { + return; + } + if (event.which === 37 || event.which === 39) { + event.preventDefault(); + event.stopImmediatePropagation(); + _this5.state(event.which === 39); + } + } + }); + } + }, { + key: '_handleHandlers', + value: function _handleHandlers() { + var _this6 = this; + + this.$on.on('click.bootstrapSwitch', function (event) { + event.preventDefault(); + event.stopPropagation(); + _this6.state(false); + return _this6.$element.trigger('focus.bootstrapSwitch'); + }); + return this.$off.on('click.bootstrapSwitch', function (event) { + event.preventDefault(); + event.stopPropagation(); + _this6.state(true); + return _this6.$element.trigger('focus.bootstrapSwitch'); + }); + } + }, { + key: '_labelHandlers', + value: function _labelHandlers() { + var _this7 = this; + + var handlers = { + click: function click(event) { + event.stopPropagation(); + }, + + + 'mousedown.bootstrapSwitch touchstart.bootstrapSwitch': function mousedownBootstrapSwitchTouchstartBootstrapSwitch(event) { + if (_this7._dragStart || _this7.options.disabled || _this7.options.readonly) { + return; + } + event.preventDefault(); + event.stopPropagation(); + _this7._dragStart = (event.pageX || event.originalEvent.touches[0].pageX) - parseInt(_this7.$container.css('margin-left'), 10); + if (_this7.options.animate) { + _this7.$wrapper.removeClass(_this7._getClass('animate')); + } + _this7.$element.trigger('focus.bootstrapSwitch'); + }, + + 'mousemove.bootstrapSwitch touchmove.bootstrapSwitch': function mousemoveBootstrapSwitchTouchmoveBootstrapSwitch(event) { + if (_this7._dragStart == null) { + return; + } + var difference = (event.pageX || event.originalEvent.touches[0].pageX) - _this7._dragStart; + event.preventDefault(); + if (difference < -_this7._handleWidth || difference > 0) { + return; + } + _this7._dragEnd = difference; + _this7.$container.css('margin-left', _this7._dragEnd + 'px'); + }, + + 'mouseup.bootstrapSwitch touchend.bootstrapSwitch': function mouseupBootstrapSwitchTouchendBootstrapSwitch(event) { + if (!_this7._dragStart) { + return; + } + event.preventDefault(); + if (_this7.options.animate) { + _this7.$wrapper.addClass(_this7._getClass('animate')); + } + if (_this7._dragEnd) { + var state = _this7._dragEnd > -(_this7._handleWidth / 2); + _this7._dragEnd = false; + _this7.state(_this7.options.inverse ? !state : state); + } else { + _this7.state(!_this7.options.state); + } + _this7._dragStart = false; + }, + + 'mouseleave.bootstrapSwitch': function mouseleaveBootstrapSwitch() { + _this7.$label.trigger('mouseup.bootstrapSwitch'); + } + }; + this.$label.on(handlers); + } + }, { + key: '_externalLabelHandler', + value: function _externalLabelHandler() { + var _this8 = this; + + var $externalLabel = this.$element.closest('label'); + $externalLabel.on('click', function (event) { + event.preventDefault(); + event.stopImmediatePropagation(); + if (event.target === $externalLabel[0]) { + _this8.toggleState(); + } + }); + } + }, { + key: '_formHandler', + value: function _formHandler() { + var $form = this.$element.closest('form'); + if ($form.data('bootstrap-switch')) { + return; + } + $form.on('reset.bootstrapSwitch', function () { + window.setTimeout(function () { + $form.find('input').filter(function () { + return $(this).data('bootstrap-switch'); + }).each(function () { + return $(this).bootstrapSwitch('state', this.checked); + }); + }, 1); + }).data('bootstrap-switch', true); + } + }, { + key: '_getClass', + value: function _getClass(name) { + return this.options.baseClass + '-' + name; + } + }, { + key: '_getClasses', + value: function _getClasses(classes) { + if (!$.isArray(classes)) { + return [this._getClass(classes)]; + } + return classes.map(this._getClass.bind(this)); + } + }]); + + return BootstrapSwitch; + }(); + + $.fn.bootstrapSwitch = function (option) { + for (var _len2 = arguments.length, args = Array(_len2 > 1 ? _len2 - 1 : 0), _key2 = 1; _key2 < _len2; _key2++) { + args[_key2 - 1] = arguments[_key2]; + } + + function reducer(ret, next) { + var $this = $(next); + var existingData = $this.data('bootstrap-switch'); + var data = existingData || new BootstrapSwitch(next, option); + if (!existingData) { + $this.data('bootstrap-switch', data); + } + if (typeof option === 'string') { + return data[option].apply(data, args); + } + return ret; + } + return Array.prototype.reduce.call(this, reducer, this); + }; + $.fn.bootstrapSwitch.Constructor = BootstrapSwitch; + $.fn.bootstrapSwitch.defaults = { + state: true, + size: null, + animate: true, + disabled: false, + readonly: false, + indeterminate: false, + inverse: false, + radioAllOff: false, + onColor: 'primary', + offColor: 'default', + onText: 'ON', + offText: 'OFF', + labelText: ' ', + handleWidth: 'auto', + labelWidth: 'auto', + baseClass: 'bootstrap-switch', + wrapperClass: 'wrapper', + onInit: function onInit() {}, + onSwitchChange: function onSwitchChange() {} + }; +}); diff --git a/hal-core/resources/web/js/lib/bootstrap-switch.min.js b/hal-core/resources/web/js/lib/bootstrap-switch.min.js new file mode 100644 index 00000000..1381dc11 --- /dev/null +++ b/hal-core/resources/web/js/lib/bootstrap-switch.min.js @@ -0,0 +1,10 @@ +/** + * bootstrap-switch - Turn checkboxes and radio buttons into toggle switches. + * + * @version v3.3.4 + * @homepage https://bttstrp.github.io/bootstrap-switch + * @author Mattia Larentis (http://larentis.eu) + * @license Apache-2.0 + */ + +(function(a,b){if('function'==typeof define&&define.amd)define(['jquery'],b);else if('undefined'!=typeof exports)b(require('jquery'));else{b(a.jquery),a.bootstrapSwitch={exports:{}}.exports}})(this,function(a){'use strict';function c(j,k){if(!(j instanceof k))throw new TypeError('Cannot call a class as a function')}var d=function(j){return j&&j.__esModule?j:{default:j}}(a),e=Object.assign||function(j){for(var l,k=1;k',{class:function(){var o=[];return o.push(l.options.state?'on':'off'),l.options.size&&o.push(l.options.size),l.options.disabled&&o.push('disabled'),l.options.readonly&&o.push('readonly'),l.options.indeterminate&&o.push('indeterminate'),l.options.inverse&&o.push('inverse'),l.$element.attr('id')&&o.push('id-'+l.$element.attr('id')),o.map(l._getClass.bind(l)).concat([l.options.baseClass],l._getClasses(l.options.wrapperClass)).join(' ')}}),this.$container=g('
',{class:this._getClass('container')}),this.$on=g('',{html:this.options.onText,class:this._getClass('handle-on')+' '+this._getClass(this.options.onColor)}),this.$off=g('',{html:this.options.offText,class:this._getClass('handle-off')+' '+this._getClass(this.options.offColor)}),this.$label=g('',{html:this.options.labelText,class:this._getClass('label')}),this.$element.on('init.bootstrapSwitch',this.options.onInit.bind(this,k)),this.$element.on('switchChange.bootstrapSwitch',function(){for(var n=arguments.length,o=Array(n),p=0;p-(l._handleWidth/2);l._dragEnd=!1,l.state(l.options.inverse?!p:p)}else l.state(!l.options.state);l._dragStart=!1}},'mouseleave.bootstrapSwitch':function(){l.$label.trigger('mouseup.bootstrapSwitch')}})}},{key:'_externalLabelHandler',value:function(){var l=this,m=this.$element.closest('label');m.on('click',function(n){n.preventDefault(),n.stopImmediatePropagation(),n.target===m[0]&&l.toggleState()})}},{key:'_formHandler',value:function(){var l=this.$element.closest('form');l.data('bootstrap-switch')||l.on('reset.bootstrapSwitch',function(){window.setTimeout(function(){l.find('input').filter(function(){return g(this).data('bootstrap-switch')}).each(function(){return g(this).bootstrapSwitch('state',this.checked)})},1)}).data('bootstrap-switch',!0)}},{key:'_getClass',value:function(l){return this.options.baseClass+'-'+l}},{key:'_getClasses',value:function(l){return g.isArray(l)?l.map(this._getClass.bind(this)):[this._getClass(l)]}}]),j}();g.fn.bootstrapSwitch=function(j){for(var l=arguments.length,m=Array(1 2)) { - throw new Error('Bootstrap\'s JavaScript requires jQuery version 1.9.1 or higher, but lower than version 3') + if ((version[0] < 2 && version[1] < 9) || (version[0] == 1 && version[1] == 9 && version[2] < 1) || (version[0] > 3)) { + throw new Error('Bootstrap\'s JavaScript requires jQuery version 1.9.1 or higher, but lower than version 4') } }(jQuery); /* ======================================================================== - * Bootstrap: transition.js v3.3.6 + * Bootstrap: transition.js v3.3.7 * http://getbootstrap.com/javascript/#transitions * ======================================================================== - * Copyright 2011-2015 Twitter, Inc. + * Copyright 2011-2016 Twitter, Inc. * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) * ======================================================================== */ @@ -77,10 +77,10 @@ if (typeof jQuery === 'undefined') { }(jQuery); /* ======================================================================== - * Bootstrap: alert.js v3.3.6 + * Bootstrap: alert.js v3.3.7 * http://getbootstrap.com/javascript/#alerts * ======================================================================== - * Copyright 2011-2015 Twitter, Inc. + * Copyright 2011-2016 Twitter, Inc. * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) * ======================================================================== */ @@ -96,7 +96,7 @@ if (typeof jQuery === 'undefined') { $(el).on('click', dismiss, this.close) } - Alert.VERSION = '3.3.6' + Alert.VERSION = '3.3.7' Alert.TRANSITION_DURATION = 150 @@ -109,7 +109,7 @@ if (typeof jQuery === 'undefined') { selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') // strip for ie7 } - var $parent = $(selector) + var $parent = $(selector === '#' ? [] : selector) if (e) e.preventDefault() @@ -172,10 +172,10 @@ if (typeof jQuery === 'undefined') { }(jQuery); /* ======================================================================== - * Bootstrap: button.js v3.3.6 + * Bootstrap: button.js v3.3.7 * http://getbootstrap.com/javascript/#buttons * ======================================================================== - * Copyright 2011-2015 Twitter, Inc. + * Copyright 2011-2016 Twitter, Inc. * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) * ======================================================================== */ @@ -192,7 +192,7 @@ if (typeof jQuery === 'undefined') { this.isLoading = false } - Button.VERSION = '3.3.6' + Button.VERSION = '3.3.7' Button.DEFAULTS = { loadingText: 'loading...' @@ -214,10 +214,10 @@ if (typeof jQuery === 'undefined') { if (state == 'loadingText') { this.isLoading = true - $el.addClass(d).attr(d, d) + $el.addClass(d).attr(d, d).prop(d, true) } else if (this.isLoading) { this.isLoading = false - $el.removeClass(d).removeAttr(d) + $el.removeClass(d).removeAttr(d).prop(d, false) } }, this), 0) } @@ -281,10 +281,15 @@ if (typeof jQuery === 'undefined') { $(document) .on('click.bs.button.data-api', '[data-toggle^="button"]', function (e) { - var $btn = $(e.target) - if (!$btn.hasClass('btn')) $btn = $btn.closest('.btn') + var $btn = $(e.target).closest('.btn') Plugin.call($btn, 'toggle') - if (!($(e.target).is('input[type="radio"]') || $(e.target).is('input[type="checkbox"]'))) e.preventDefault() + if (!($(e.target).is('input[type="radio"], input[type="checkbox"]'))) { + // Prevent double click on radios, and the double selections (so cancellation) on checkboxes + e.preventDefault() + // The target component still receive the focus + if ($btn.is('input,button')) $btn.trigger('focus') + else $btn.find('input:visible,button:visible').first().trigger('focus') + } }) .on('focus.bs.button.data-api blur.bs.button.data-api', '[data-toggle^="button"]', function (e) { $(e.target).closest('.btn').toggleClass('focus', /^focus(in)?$/.test(e.type)) @@ -293,10 +298,10 @@ if (typeof jQuery === 'undefined') { }(jQuery); /* ======================================================================== - * Bootstrap: carousel.js v3.3.6 + * Bootstrap: carousel.js v3.3.7 * http://getbootstrap.com/javascript/#carousel * ======================================================================== - * Copyright 2011-2015 Twitter, Inc. + * Copyright 2011-2016 Twitter, Inc. * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) * ======================================================================== */ @@ -324,7 +329,7 @@ if (typeof jQuery === 'undefined') { .on('mouseleave.bs.carousel', $.proxy(this.cycle, this)) } - Carousel.VERSION = '3.3.6' + Carousel.VERSION = '3.3.7' Carousel.TRANSITION_DURATION = 600 @@ -531,13 +536,14 @@ if (typeof jQuery === 'undefined') { }(jQuery); /* ======================================================================== - * Bootstrap: collapse.js v3.3.6 + * Bootstrap: collapse.js v3.3.7 * http://getbootstrap.com/javascript/#collapse * ======================================================================== - * Copyright 2011-2015 Twitter, Inc. + * Copyright 2011-2016 Twitter, Inc. * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) * ======================================================================== */ +/* jshint latedef: false */ +function ($) { 'use strict'; @@ -561,7 +567,7 @@ if (typeof jQuery === 'undefined') { if (this.options.toggle) this.toggle() } - Collapse.VERSION = '3.3.6' + Collapse.VERSION = '3.3.7' Collapse.TRANSITION_DURATION = 350 @@ -743,10 +749,10 @@ if (typeof jQuery === 'undefined') { }(jQuery); /* ======================================================================== - * Bootstrap: dropdown.js v3.3.6 + * Bootstrap: dropdown.js v3.3.7 * http://getbootstrap.com/javascript/#dropdowns * ======================================================================== - * Copyright 2011-2015 Twitter, Inc. + * Copyright 2011-2016 Twitter, Inc. * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) * ======================================================================== */ @@ -763,7 +769,7 @@ if (typeof jQuery === 'undefined') { $(element).on('click.bs.dropdown', this.toggle) } - Dropdown.VERSION = '3.3.6' + Dropdown.VERSION = '3.3.7' function getParent($this) { var selector = $this.attr('data-target') @@ -909,10 +915,10 @@ if (typeof jQuery === 'undefined') { }(jQuery); /* ======================================================================== - * Bootstrap: modal.js v3.3.6 + * Bootstrap: modal.js v3.3.7 * http://getbootstrap.com/javascript/#modals * ======================================================================== - * Copyright 2011-2015 Twitter, Inc. + * Copyright 2011-2016 Twitter, Inc. * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) * ======================================================================== */ @@ -943,7 +949,7 @@ if (typeof jQuery === 'undefined') { } } - Modal.VERSION = '3.3.6' + Modal.VERSION = '3.3.7' Modal.TRANSITION_DURATION = 300 Modal.BACKDROP_TRANSITION_DURATION = 150 @@ -1050,7 +1056,9 @@ if (typeof jQuery === 'undefined') { $(document) .off('focusin.bs.modal') // guard against infinite focus loop .on('focusin.bs.modal', $.proxy(function (e) { - if (this.$element[0] !== e.target && !this.$element.has(e.target).length) { + if (document !== e.target && + this.$element[0] !== e.target && + !this.$element.has(e.target).length) { this.$element.trigger('focus') } }, this)) @@ -1247,11 +1255,11 @@ if (typeof jQuery === 'undefined') { }(jQuery); /* ======================================================================== - * Bootstrap: tooltip.js v3.3.6 + * Bootstrap: tooltip.js v3.3.7 * http://getbootstrap.com/javascript/#tooltip * Inspired by the original jQuery.tipsy by Jason Frame * ======================================================================== - * Copyright 2011-2015 Twitter, Inc. + * Copyright 2011-2016 Twitter, Inc. * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) * ======================================================================== */ @@ -1274,7 +1282,7 @@ if (typeof jQuery === 'undefined') { this.init('tooltip', element, options) } - Tooltip.VERSION = '3.3.6' + Tooltip.VERSION = '3.3.7' Tooltip.TRANSITION_DURATION = 150 @@ -1565,9 +1573,11 @@ if (typeof jQuery === 'undefined') { function complete() { if (that.hoverState != 'in') $tip.detach() - that.$element - .removeAttr('aria-describedby') - .trigger('hidden.bs.' + that.type) + if (that.$element) { // TODO: Check whether guarding this code with this `if` is really necessary. + that.$element + .removeAttr('aria-describedby') + .trigger('hidden.bs.' + that.type) + } callback && callback() } @@ -1610,7 +1620,10 @@ if (typeof jQuery === 'undefined') { // width and height are missing in IE8, so compute them manually; see https://github.com/twbs/bootstrap/issues/14093 elRect = $.extend({}, elRect, { width: elRect.right - elRect.left, height: elRect.bottom - elRect.top }) } - var elOffset = isBody ? { top: 0, left: 0 } : $element.offset() + var isSvg = window.SVGElement && el instanceof window.SVGElement + // Avoid using $.offset() on SVGs since it gives incorrect results in jQuery 3. + // See https://github.com/twbs/bootstrap/issues/20280 + var elOffset = isBody ? { top: 0, left: 0 } : (isSvg ? null : $element.offset()) var scroll = { scroll: isBody ? document.documentElement.scrollTop || document.body.scrollTop : $element.scrollTop() } var outerDims = isBody ? { width: $(window).width(), height: $(window).height() } : null @@ -1726,6 +1739,7 @@ if (typeof jQuery === 'undefined') { that.$tip = null that.$arrow = null that.$viewport = null + that.$element = null }) } @@ -1762,10 +1776,10 @@ if (typeof jQuery === 'undefined') { }(jQuery); /* ======================================================================== - * Bootstrap: popover.js v3.3.6 + * Bootstrap: popover.js v3.3.7 * http://getbootstrap.com/javascript/#popovers * ======================================================================== - * Copyright 2011-2015 Twitter, Inc. + * Copyright 2011-2016 Twitter, Inc. * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) * ======================================================================== */ @@ -1782,7 +1796,7 @@ if (typeof jQuery === 'undefined') { if (!$.fn.tooltip) throw new Error('Popover requires tooltip.js') - Popover.VERSION = '3.3.6' + Popover.VERSION = '3.3.7' Popover.DEFAULTS = $.extend({}, $.fn.tooltip.Constructor.DEFAULTS, { placement: 'right', @@ -1871,10 +1885,10 @@ if (typeof jQuery === 'undefined') { }(jQuery); /* ======================================================================== - * Bootstrap: scrollspy.js v3.3.6 + * Bootstrap: scrollspy.js v3.3.7 * http://getbootstrap.com/javascript/#scrollspy * ======================================================================== - * Copyright 2011-2015 Twitter, Inc. + * Copyright 2011-2016 Twitter, Inc. * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) * ======================================================================== */ @@ -1900,7 +1914,7 @@ if (typeof jQuery === 'undefined') { this.process() } - ScrollSpy.VERSION = '3.3.6' + ScrollSpy.VERSION = '3.3.7' ScrollSpy.DEFAULTS = { offset: 10 @@ -2044,10 +2058,10 @@ if (typeof jQuery === 'undefined') { }(jQuery); /* ======================================================================== - * Bootstrap: tab.js v3.3.6 + * Bootstrap: tab.js v3.3.7 * http://getbootstrap.com/javascript/#tabs * ======================================================================== - * Copyright 2011-2015 Twitter, Inc. + * Copyright 2011-2016 Twitter, Inc. * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) * ======================================================================== */ @@ -2064,7 +2078,7 @@ if (typeof jQuery === 'undefined') { // jscs:enable requireDollarBeforejQueryAssignment } - Tab.VERSION = '3.3.6' + Tab.VERSION = '3.3.7' Tab.TRANSITION_DURATION = 150 @@ -2200,10 +2214,10 @@ if (typeof jQuery === 'undefined') { }(jQuery); /* ======================================================================== - * Bootstrap: affix.js v3.3.6 + * Bootstrap: affix.js v3.3.7 * http://getbootstrap.com/javascript/#affix * ======================================================================== - * Copyright 2011-2015 Twitter, Inc. + * Copyright 2011-2016 Twitter, Inc. * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) * ======================================================================== */ @@ -2229,7 +2243,7 @@ if (typeof jQuery === 'undefined') { this.checkPosition() } - Affix.VERSION = '3.3.6' + Affix.VERSION = '3.3.7' Affix.RESET = 'affix affix-top affix-bottom' diff --git a/hal-core/resources/web/js/lib/bootstrap.min.js b/hal-core/resources/web/js/lib/bootstrap.min.js new file mode 100644 index 00000000..9bcd2fcc --- /dev/null +++ b/hal-core/resources/web/js/lib/bootstrap.min.js @@ -0,0 +1,7 @@ +/*! + * Bootstrap v3.3.7 (http://getbootstrap.com) + * Copyright 2011-2016 Twitter, Inc. + * Licensed under the MIT license + */ +if("undefined"==typeof jQuery)throw new Error("Bootstrap's JavaScript requires jQuery");+function(a){"use strict";var b=a.fn.jquery.split(" ")[0].split(".");if(b[0]<2&&b[1]<9||1==b[0]&&9==b[1]&&b[2]<1||b[0]>3)throw new Error("Bootstrap's JavaScript requires jQuery version 1.9.1 or higher, but lower than version 4")}(jQuery),+function(a){"use strict";function b(){var a=document.createElement("bootstrap"),b={WebkitTransition:"webkitTransitionEnd",MozTransition:"transitionend",OTransition:"oTransitionEnd otransitionend",transition:"transitionend"};for(var c in b)if(void 0!==a.style[c])return{end:b[c]};return!1}a.fn.emulateTransitionEnd=function(b){var c=!1,d=this;a(this).one("bsTransitionEnd",function(){c=!0});var e=function(){c||a(d).trigger(a.support.transition.end)};return setTimeout(e,b),this},a(function(){a.support.transition=b(),a.support.transition&&(a.event.special.bsTransitionEnd={bindType:a.support.transition.end,delegateType:a.support.transition.end,handle:function(b){if(a(b.target).is(this))return b.handleObj.handler.apply(this,arguments)}})})}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var c=a(this),e=c.data("bs.alert");e||c.data("bs.alert",e=new d(this)),"string"==typeof b&&e[b].call(c)})}var c='[data-dismiss="alert"]',d=function(b){a(b).on("click",c,this.close)};d.VERSION="3.3.7",d.TRANSITION_DURATION=150,d.prototype.close=function(b){function c(){g.detach().trigger("closed.bs.alert").remove()}var e=a(this),f=e.attr("data-target");f||(f=e.attr("href"),f=f&&f.replace(/.*(?=#[^\s]*$)/,""));var g=a("#"===f?[]:f);b&&b.preventDefault(),g.length||(g=e.closest(".alert")),g.trigger(b=a.Event("close.bs.alert")),b.isDefaultPrevented()||(g.removeClass("in"),a.support.transition&&g.hasClass("fade")?g.one("bsTransitionEnd",c).emulateTransitionEnd(d.TRANSITION_DURATION):c())};var e=a.fn.alert;a.fn.alert=b,a.fn.alert.Constructor=d,a.fn.alert.noConflict=function(){return a.fn.alert=e,this},a(document).on("click.bs.alert.data-api",c,d.prototype.close)}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.button"),f="object"==typeof b&&b;e||d.data("bs.button",e=new c(this,f)),"toggle"==b?e.toggle():b&&e.setState(b)})}var c=function(b,d){this.$element=a(b),this.options=a.extend({},c.DEFAULTS,d),this.isLoading=!1};c.VERSION="3.3.7",c.DEFAULTS={loadingText:"loading..."},c.prototype.setState=function(b){var c="disabled",d=this.$element,e=d.is("input")?"val":"html",f=d.data();b+="Text",null==f.resetText&&d.data("resetText",d[e]()),setTimeout(a.proxy(function(){d[e](null==f[b]?this.options[b]:f[b]),"loadingText"==b?(this.isLoading=!0,d.addClass(c).attr(c,c).prop(c,!0)):this.isLoading&&(this.isLoading=!1,d.removeClass(c).removeAttr(c).prop(c,!1))},this),0)},c.prototype.toggle=function(){var a=!0,b=this.$element.closest('[data-toggle="buttons"]');if(b.length){var c=this.$element.find("input");"radio"==c.prop("type")?(c.prop("checked")&&(a=!1),b.find(".active").removeClass("active"),this.$element.addClass("active")):"checkbox"==c.prop("type")&&(c.prop("checked")!==this.$element.hasClass("active")&&(a=!1),this.$element.toggleClass("active")),c.prop("checked",this.$element.hasClass("active")),a&&c.trigger("change")}else this.$element.attr("aria-pressed",!this.$element.hasClass("active")),this.$element.toggleClass("active")};var d=a.fn.button;a.fn.button=b,a.fn.button.Constructor=c,a.fn.button.noConflict=function(){return a.fn.button=d,this},a(document).on("click.bs.button.data-api",'[data-toggle^="button"]',function(c){var d=a(c.target).closest(".btn");b.call(d,"toggle"),a(c.target).is('input[type="radio"], input[type="checkbox"]')||(c.preventDefault(),d.is("input,button")?d.trigger("focus"):d.find("input:visible,button:visible").first().trigger("focus"))}).on("focus.bs.button.data-api blur.bs.button.data-api",'[data-toggle^="button"]',function(b){a(b.target).closest(".btn").toggleClass("focus",/^focus(in)?$/.test(b.type))})}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.carousel"),f=a.extend({},c.DEFAULTS,d.data(),"object"==typeof b&&b),g="string"==typeof b?b:f.slide;e||d.data("bs.carousel",e=new c(this,f)),"number"==typeof b?e.to(b):g?e[g]():f.interval&&e.pause().cycle()})}var c=function(b,c){this.$element=a(b),this.$indicators=this.$element.find(".carousel-indicators"),this.options=c,this.paused=null,this.sliding=null,this.interval=null,this.$active=null,this.$items=null,this.options.keyboard&&this.$element.on("keydown.bs.carousel",a.proxy(this.keydown,this)),"hover"==this.options.pause&&!("ontouchstart"in document.documentElement)&&this.$element.on("mouseenter.bs.carousel",a.proxy(this.pause,this)).on("mouseleave.bs.carousel",a.proxy(this.cycle,this))};c.VERSION="3.3.7",c.TRANSITION_DURATION=600,c.DEFAULTS={interval:5e3,pause:"hover",wrap:!0,keyboard:!0},c.prototype.keydown=function(a){if(!/input|textarea/i.test(a.target.tagName)){switch(a.which){case 37:this.prev();break;case 39:this.next();break;default:return}a.preventDefault()}},c.prototype.cycle=function(b){return b||(this.paused=!1),this.interval&&clearInterval(this.interval),this.options.interval&&!this.paused&&(this.interval=setInterval(a.proxy(this.next,this),this.options.interval)),this},c.prototype.getItemIndex=function(a){return this.$items=a.parent().children(".item"),this.$items.index(a||this.$active)},c.prototype.getItemForDirection=function(a,b){var c=this.getItemIndex(b),d="prev"==a&&0===c||"next"==a&&c==this.$items.length-1;if(d&&!this.options.wrap)return b;var e="prev"==a?-1:1,f=(c+e)%this.$items.length;return this.$items.eq(f)},c.prototype.to=function(a){var b=this,c=this.getItemIndex(this.$active=this.$element.find(".item.active"));if(!(a>this.$items.length-1||a<0))return this.sliding?this.$element.one("slid.bs.carousel",function(){b.to(a)}):c==a?this.pause().cycle():this.slide(a>c?"next":"prev",this.$items.eq(a))},c.prototype.pause=function(b){return b||(this.paused=!0),this.$element.find(".next, .prev").length&&a.support.transition&&(this.$element.trigger(a.support.transition.end),this.cycle(!0)),this.interval=clearInterval(this.interval),this},c.prototype.next=function(){if(!this.sliding)return this.slide("next")},c.prototype.prev=function(){if(!this.sliding)return this.slide("prev")},c.prototype.slide=function(b,d){var e=this.$element.find(".item.active"),f=d||this.getItemForDirection(b,e),g=this.interval,h="next"==b?"left":"right",i=this;if(f.hasClass("active"))return this.sliding=!1;var j=f[0],k=a.Event("slide.bs.carousel",{relatedTarget:j,direction:h});if(this.$element.trigger(k),!k.isDefaultPrevented()){if(this.sliding=!0,g&&this.pause(),this.$indicators.length){this.$indicators.find(".active").removeClass("active");var l=a(this.$indicators.children()[this.getItemIndex(f)]);l&&l.addClass("active")}var m=a.Event("slid.bs.carousel",{relatedTarget:j,direction:h});return a.support.transition&&this.$element.hasClass("slide")?(f.addClass(b),f[0].offsetWidth,e.addClass(h),f.addClass(h),e.one("bsTransitionEnd",function(){f.removeClass([b,h].join(" ")).addClass("active"),e.removeClass(["active",h].join(" ")),i.sliding=!1,setTimeout(function(){i.$element.trigger(m)},0)}).emulateTransitionEnd(c.TRANSITION_DURATION)):(e.removeClass("active"),f.addClass("active"),this.sliding=!1,this.$element.trigger(m)),g&&this.cycle(),this}};var d=a.fn.carousel;a.fn.carousel=b,a.fn.carousel.Constructor=c,a.fn.carousel.noConflict=function(){return a.fn.carousel=d,this};var e=function(c){var d,e=a(this),f=a(e.attr("data-target")||(d=e.attr("href"))&&d.replace(/.*(?=#[^\s]+$)/,""));if(f.hasClass("carousel")){var g=a.extend({},f.data(),e.data()),h=e.attr("data-slide-to");h&&(g.interval=!1),b.call(f,g),h&&f.data("bs.carousel").to(h),c.preventDefault()}};a(document).on("click.bs.carousel.data-api","[data-slide]",e).on("click.bs.carousel.data-api","[data-slide-to]",e),a(window).on("load",function(){a('[data-ride="carousel"]').each(function(){var c=a(this);b.call(c,c.data())})})}(jQuery),+function(a){"use strict";function b(b){var c,d=b.attr("data-target")||(c=b.attr("href"))&&c.replace(/.*(?=#[^\s]+$)/,"");return a(d)}function c(b){return this.each(function(){var c=a(this),e=c.data("bs.collapse"),f=a.extend({},d.DEFAULTS,c.data(),"object"==typeof b&&b);!e&&f.toggle&&/show|hide/.test(b)&&(f.toggle=!1),e||c.data("bs.collapse",e=new d(this,f)),"string"==typeof b&&e[b]()})}var d=function(b,c){this.$element=a(b),this.options=a.extend({},d.DEFAULTS,c),this.$trigger=a('[data-toggle="collapse"][href="#'+b.id+'"],[data-toggle="collapse"][data-target="#'+b.id+'"]'),this.transitioning=null,this.options.parent?this.$parent=this.getParent():this.addAriaAndCollapsedClass(this.$element,this.$trigger),this.options.toggle&&this.toggle()};d.VERSION="3.3.7",d.TRANSITION_DURATION=350,d.DEFAULTS={toggle:!0},d.prototype.dimension=function(){var a=this.$element.hasClass("width");return a?"width":"height"},d.prototype.show=function(){if(!this.transitioning&&!this.$element.hasClass("in")){var b,e=this.$parent&&this.$parent.children(".panel").children(".in, .collapsing");if(!(e&&e.length&&(b=e.data("bs.collapse"),b&&b.transitioning))){var f=a.Event("show.bs.collapse");if(this.$element.trigger(f),!f.isDefaultPrevented()){e&&e.length&&(c.call(e,"hide"),b||e.data("bs.collapse",null));var g=this.dimension();this.$element.removeClass("collapse").addClass("collapsing")[g](0).attr("aria-expanded",!0),this.$trigger.removeClass("collapsed").attr("aria-expanded",!0),this.transitioning=1;var h=function(){this.$element.removeClass("collapsing").addClass("collapse in")[g](""),this.transitioning=0,this.$element.trigger("shown.bs.collapse")};if(!a.support.transition)return h.call(this);var i=a.camelCase(["scroll",g].join("-"));this.$element.one("bsTransitionEnd",a.proxy(h,this)).emulateTransitionEnd(d.TRANSITION_DURATION)[g](this.$element[0][i])}}}},d.prototype.hide=function(){if(!this.transitioning&&this.$element.hasClass("in")){var b=a.Event("hide.bs.collapse");if(this.$element.trigger(b),!b.isDefaultPrevented()){var c=this.dimension();this.$element[c](this.$element[c]())[0].offsetHeight,this.$element.addClass("collapsing").removeClass("collapse in").attr("aria-expanded",!1),this.$trigger.addClass("collapsed").attr("aria-expanded",!1),this.transitioning=1;var e=function(){this.transitioning=0,this.$element.removeClass("collapsing").addClass("collapse").trigger("hidden.bs.collapse")};return a.support.transition?void this.$element[c](0).one("bsTransitionEnd",a.proxy(e,this)).emulateTransitionEnd(d.TRANSITION_DURATION):e.call(this)}}},d.prototype.toggle=function(){this[this.$element.hasClass("in")?"hide":"show"]()},d.prototype.getParent=function(){return a(this.options.parent).find('[data-toggle="collapse"][data-parent="'+this.options.parent+'"]').each(a.proxy(function(c,d){var e=a(d);this.addAriaAndCollapsedClass(b(e),e)},this)).end()},d.prototype.addAriaAndCollapsedClass=function(a,b){var c=a.hasClass("in");a.attr("aria-expanded",c),b.toggleClass("collapsed",!c).attr("aria-expanded",c)};var e=a.fn.collapse;a.fn.collapse=c,a.fn.collapse.Constructor=d,a.fn.collapse.noConflict=function(){return a.fn.collapse=e,this},a(document).on("click.bs.collapse.data-api",'[data-toggle="collapse"]',function(d){var e=a(this);e.attr("data-target")||d.preventDefault();var f=b(e),g=f.data("bs.collapse"),h=g?"toggle":e.data();c.call(f,h)})}(jQuery),+function(a){"use strict";function b(b){var c=b.attr("data-target");c||(c=b.attr("href"),c=c&&/#[A-Za-z]/.test(c)&&c.replace(/.*(?=#[^\s]*$)/,""));var d=c&&a(c);return d&&d.length?d:b.parent()}function c(c){c&&3===c.which||(a(e).remove(),a(f).each(function(){var d=a(this),e=b(d),f={relatedTarget:this};e.hasClass("open")&&(c&&"click"==c.type&&/input|textarea/i.test(c.target.tagName)&&a.contains(e[0],c.target)||(e.trigger(c=a.Event("hide.bs.dropdown",f)),c.isDefaultPrevented()||(d.attr("aria-expanded","false"),e.removeClass("open").trigger(a.Event("hidden.bs.dropdown",f)))))}))}function d(b){return this.each(function(){var c=a(this),d=c.data("bs.dropdown");d||c.data("bs.dropdown",d=new g(this)),"string"==typeof b&&d[b].call(c)})}var e=".dropdown-backdrop",f='[data-toggle="dropdown"]',g=function(b){a(b).on("click.bs.dropdown",this.toggle)};g.VERSION="3.3.7",g.prototype.toggle=function(d){var e=a(this);if(!e.is(".disabled, :disabled")){var f=b(e),g=f.hasClass("open");if(c(),!g){"ontouchstart"in document.documentElement&&!f.closest(".navbar-nav").length&&a(document.createElement("div")).addClass("dropdown-backdrop").insertAfter(a(this)).on("click",c);var h={relatedTarget:this};if(f.trigger(d=a.Event("show.bs.dropdown",h)),d.isDefaultPrevented())return;e.trigger("focus").attr("aria-expanded","true"),f.toggleClass("open").trigger(a.Event("shown.bs.dropdown",h))}return!1}},g.prototype.keydown=function(c){if(/(38|40|27|32)/.test(c.which)&&!/input|textarea/i.test(c.target.tagName)){var d=a(this);if(c.preventDefault(),c.stopPropagation(),!d.is(".disabled, :disabled")){var e=b(d),g=e.hasClass("open");if(!g&&27!=c.which||g&&27==c.which)return 27==c.which&&e.find(f).trigger("focus"),d.trigger("click");var h=" li:not(.disabled):visible a",i=e.find(".dropdown-menu"+h);if(i.length){var j=i.index(c.target);38==c.which&&j>0&&j--,40==c.which&&jdocument.documentElement.clientHeight;this.$element.css({paddingLeft:!this.bodyIsOverflowing&&a?this.scrollbarWidth:"",paddingRight:this.bodyIsOverflowing&&!a?this.scrollbarWidth:""})},c.prototype.resetAdjustments=function(){this.$element.css({paddingLeft:"",paddingRight:""})},c.prototype.checkScrollbar=function(){var a=window.innerWidth;if(!a){var b=document.documentElement.getBoundingClientRect();a=b.right-Math.abs(b.left)}this.bodyIsOverflowing=document.body.clientWidth
',trigger:"hover focus",title:"",delay:0,html:!1,container:!1,viewport:{selector:"body",padding:0}},c.prototype.init=function(b,c,d){if(this.enabled=!0,this.type=b,this.$element=a(c),this.options=this.getOptions(d),this.$viewport=this.options.viewport&&a(a.isFunction(this.options.viewport)?this.options.viewport.call(this,this.$element):this.options.viewport.selector||this.options.viewport),this.inState={click:!1,hover:!1,focus:!1},this.$element[0]instanceof document.constructor&&!this.options.selector)throw new Error("`selector` option must be specified when initializing "+this.type+" on the window.document object!");for(var e=this.options.trigger.split(" "),f=e.length;f--;){var g=e[f];if("click"==g)this.$element.on("click."+this.type,this.options.selector,a.proxy(this.toggle,this));else if("manual"!=g){var h="hover"==g?"mouseenter":"focusin",i="hover"==g?"mouseleave":"focusout";this.$element.on(h+"."+this.type,this.options.selector,a.proxy(this.enter,this)),this.$element.on(i+"."+this.type,this.options.selector,a.proxy(this.leave,this))}}this.options.selector?this._options=a.extend({},this.options,{trigger:"manual",selector:""}):this.fixTitle()},c.prototype.getDefaults=function(){return c.DEFAULTS},c.prototype.getOptions=function(b){return b=a.extend({},this.getDefaults(),this.$element.data(),b),b.delay&&"number"==typeof b.delay&&(b.delay={show:b.delay,hide:b.delay}),b},c.prototype.getDelegateOptions=function(){var b={},c=this.getDefaults();return this._options&&a.each(this._options,function(a,d){c[a]!=d&&(b[a]=d)}),b},c.prototype.enter=function(b){var c=b instanceof this.constructor?b:a(b.currentTarget).data("bs."+this.type);return c||(c=new this.constructor(b.currentTarget,this.getDelegateOptions()),a(b.currentTarget).data("bs."+this.type,c)),b instanceof a.Event&&(c.inState["focusin"==b.type?"focus":"hover"]=!0),c.tip().hasClass("in")||"in"==c.hoverState?void(c.hoverState="in"):(clearTimeout(c.timeout),c.hoverState="in",c.options.delay&&c.options.delay.show?void(c.timeout=setTimeout(function(){"in"==c.hoverState&&c.show()},c.options.delay.show)):c.show())},c.prototype.isInStateTrue=function(){for(var a in this.inState)if(this.inState[a])return!0;return!1},c.prototype.leave=function(b){var c=b instanceof this.constructor?b:a(b.currentTarget).data("bs."+this.type);if(c||(c=new this.constructor(b.currentTarget,this.getDelegateOptions()),a(b.currentTarget).data("bs."+this.type,c)),b instanceof a.Event&&(c.inState["focusout"==b.type?"focus":"hover"]=!1),!c.isInStateTrue())return clearTimeout(c.timeout),c.hoverState="out",c.options.delay&&c.options.delay.hide?void(c.timeout=setTimeout(function(){"out"==c.hoverState&&c.hide()},c.options.delay.hide)):c.hide()},c.prototype.show=function(){var b=a.Event("show.bs."+this.type);if(this.hasContent()&&this.enabled){this.$element.trigger(b);var d=a.contains(this.$element[0].ownerDocument.documentElement,this.$element[0]);if(b.isDefaultPrevented()||!d)return;var e=this,f=this.tip(),g=this.getUID(this.type);this.setContent(),f.attr("id",g),this.$element.attr("aria-describedby",g),this.options.animation&&f.addClass("fade");var h="function"==typeof this.options.placement?this.options.placement.call(this,f[0],this.$element[0]):this.options.placement,i=/\s?auto?\s?/i,j=i.test(h);j&&(h=h.replace(i,"")||"top"),f.detach().css({top:0,left:0,display:"block"}).addClass(h).data("bs."+this.type,this),this.options.container?f.appendTo(this.options.container):f.insertAfter(this.$element),this.$element.trigger("inserted.bs."+this.type);var k=this.getPosition(),l=f[0].offsetWidth,m=f[0].offsetHeight;if(j){var n=h,o=this.getPosition(this.$viewport);h="bottom"==h&&k.bottom+m>o.bottom?"top":"top"==h&&k.top-mo.width?"left":"left"==h&&k.left-lg.top+g.height&&(e.top=g.top+g.height-i)}else{var j=b.left-f,k=b.left+f+c;jg.right&&(e.left=g.left+g.width-k)}return e},c.prototype.getTitle=function(){var a,b=this.$element,c=this.options;return a=b.attr("data-original-title")||("function"==typeof c.title?c.title.call(b[0]):c.title)},c.prototype.getUID=function(a){do a+=~~(1e6*Math.random());while(document.getElementById(a));return a},c.prototype.tip=function(){if(!this.$tip&&(this.$tip=a(this.options.template),1!=this.$tip.length))throw new Error(this.type+" `template` option must consist of exactly 1 top-level element!");return this.$tip},c.prototype.arrow=function(){return this.$arrow=this.$arrow||this.tip().find(".tooltip-arrow")},c.prototype.enable=function(){this.enabled=!0},c.prototype.disable=function(){this.enabled=!1},c.prototype.toggleEnabled=function(){this.enabled=!this.enabled},c.prototype.toggle=function(b){var c=this;b&&(c=a(b.currentTarget).data("bs."+this.type),c||(c=new this.constructor(b.currentTarget,this.getDelegateOptions()),a(b.currentTarget).data("bs."+this.type,c))),b?(c.inState.click=!c.inState.click,c.isInStateTrue()?c.enter(c):c.leave(c)):c.tip().hasClass("in")?c.leave(c):c.enter(c)},c.prototype.destroy=function(){var a=this;clearTimeout(this.timeout),this.hide(function(){a.$element.off("."+a.type).removeData("bs."+a.type),a.$tip&&a.$tip.detach(),a.$tip=null,a.$arrow=null,a.$viewport=null,a.$element=null})};var d=a.fn.tooltip;a.fn.tooltip=b,a.fn.tooltip.Constructor=c,a.fn.tooltip.noConflict=function(){return a.fn.tooltip=d,this}}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.popover"),f="object"==typeof b&&b;!e&&/destroy|hide/.test(b)||(e||d.data("bs.popover",e=new c(this,f)),"string"==typeof b&&e[b]())})}var c=function(a,b){this.init("popover",a,b)};if(!a.fn.tooltip)throw new Error("Popover requires tooltip.js");c.VERSION="3.3.7",c.DEFAULTS=a.extend({},a.fn.tooltip.Constructor.DEFAULTS,{placement:"right",trigger:"click",content:"",template:''}),c.prototype=a.extend({},a.fn.tooltip.Constructor.prototype),c.prototype.constructor=c,c.prototype.getDefaults=function(){return c.DEFAULTS},c.prototype.setContent=function(){var a=this.tip(),b=this.getTitle(),c=this.getContent();a.find(".popover-title")[this.options.html?"html":"text"](b),a.find(".popover-content").children().detach().end()[this.options.html?"string"==typeof c?"html":"append":"text"](c),a.removeClass("fade top bottom left right in"),a.find(".popover-title").html()||a.find(".popover-title").hide()},c.prototype.hasContent=function(){return this.getTitle()||this.getContent()},c.prototype.getContent=function(){var a=this.$element,b=this.options;return a.attr("data-content")||("function"==typeof b.content?b.content.call(a[0]):b.content)},c.prototype.arrow=function(){return this.$arrow=this.$arrow||this.tip().find(".arrow")};var d=a.fn.popover;a.fn.popover=b,a.fn.popover.Constructor=c,a.fn.popover.noConflict=function(){return a.fn.popover=d,this}}(jQuery),+function(a){"use strict";function b(c,d){this.$body=a(document.body),this.$scrollElement=a(a(c).is(document.body)?window:c),this.options=a.extend({},b.DEFAULTS,d),this.selector=(this.options.target||"")+" .nav li > a",this.offsets=[],this.targets=[],this.activeTarget=null,this.scrollHeight=0,this.$scrollElement.on("scroll.bs.scrollspy",a.proxy(this.process,this)),this.refresh(),this.process()}function c(c){return this.each(function(){var d=a(this),e=d.data("bs.scrollspy"),f="object"==typeof c&&c;e||d.data("bs.scrollspy",e=new b(this,f)),"string"==typeof c&&e[c]()})}b.VERSION="3.3.7",b.DEFAULTS={offset:10},b.prototype.getScrollHeight=function(){return this.$scrollElement[0].scrollHeight||Math.max(this.$body[0].scrollHeight,document.documentElement.scrollHeight)},b.prototype.refresh=function(){var b=this,c="offset",d=0;this.offsets=[],this.targets=[],this.scrollHeight=this.getScrollHeight(),a.isWindow(this.$scrollElement[0])||(c="position",d=this.$scrollElement.scrollTop()),this.$body.find(this.selector).map(function(){var b=a(this),e=b.data("target")||b.attr("href"),f=/^#./.test(e)&&a(e);return f&&f.length&&f.is(":visible")&&[[f[c]().top+d,e]]||null}).sort(function(a,b){return a[0]-b[0]}).each(function(){b.offsets.push(this[0]),b.targets.push(this[1])})},b.prototype.process=function(){var a,b=this.$scrollElement.scrollTop()+this.options.offset,c=this.getScrollHeight(),d=this.options.offset+c-this.$scrollElement.height(),e=this.offsets,f=this.targets,g=this.activeTarget;if(this.scrollHeight!=c&&this.refresh(),b>=d)return g!=(a=f[f.length-1])&&this.activate(a);if(g&&b=e[a]&&(void 0===e[a+1]||b .dropdown-menu > .active").removeClass("active").end().find('[data-toggle="tab"]').attr("aria-expanded",!1),b.addClass("active").find('[data-toggle="tab"]').attr("aria-expanded",!0),h?(b[0].offsetWidth,b.addClass("in")):b.removeClass("fade"),b.parent(".dropdown-menu").length&&b.closest("li.dropdown").addClass("active").end().find('[data-toggle="tab"]').attr("aria-expanded",!0),e&&e()}var g=d.find("> .active"),h=e&&a.support.transition&&(g.length&&g.hasClass("fade")||!!d.find("> .fade").length);g.length&&h?g.one("bsTransitionEnd",f).emulateTransitionEnd(c.TRANSITION_DURATION):f(),g.removeClass("in")};var d=a.fn.tab;a.fn.tab=b,a.fn.tab.Constructor=c,a.fn.tab.noConflict=function(){return a.fn.tab=d,this};var e=function(c){c.preventDefault(),b.call(a(this),"show")};a(document).on("click.bs.tab.data-api",'[data-toggle="tab"]',e).on("click.bs.tab.data-api",'[data-toggle="pill"]',e)}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.affix"),f="object"==typeof b&&b;e||d.data("bs.affix",e=new c(this,f)),"string"==typeof b&&e[b]()})}var c=function(b,d){this.options=a.extend({},c.DEFAULTS,d),this.$target=a(this.options.target).on("scroll.bs.affix.data-api",a.proxy(this.checkPosition,this)).on("click.bs.affix.data-api",a.proxy(this.checkPositionWithEventLoop,this)),this.$element=a(b),this.affixed=null,this.unpin=null,this.pinnedOffset=null,this.checkPosition()};c.VERSION="3.3.7",c.RESET="affix affix-top affix-bottom",c.DEFAULTS={offset:0,target:window},c.prototype.getState=function(a,b,c,d){var e=this.$target.scrollTop(),f=this.$element.offset(),g=this.$target.height();if(null!=c&&"top"==this.affixed)return e=a-d&&"bottom"},c.prototype.getPinnedOffset=function(){if(this.pinnedOffset)return this.pinnedOffset;this.$element.removeClass(c.RESET).addClass("affix");var a=this.$target.scrollTop(),b=this.$element.offset();return this.pinnedOffset=b.top-a},c.prototype.checkPositionWithEventLoop=function(){setTimeout(a.proxy(this.checkPosition,this),1)},c.prototype.checkPosition=function(){if(this.$element.is(":visible")){var b=this.$element.height(),d=this.options.offset,e=d.top,f=d.bottom,g=Math.max(a(document).height(),a(document.body).height());"object"!=typeof d&&(f=e=d),"function"==typeof e&&(e=d.top(this.$element)),"function"==typeof f&&(f=d.bottom(this.$element));var h=this.getState(g,b,e,f);if(this.affixed!=h){null!=this.unpin&&this.$element.css("top","");var i="affix"+(h?"-"+h:""),j=a.Event(i+".bs.affix");if(this.$element.trigger(j),j.isDefaultPrevented())return;this.affixed=h,this.unpin="bottom"==h?this.getPinnedOffset():null,this.$element.removeClass(c.RESET).addClass(i).trigger(i.replace("affix","affixed")+".bs.affix")}"bottom"==h&&this.$element.offset({top:g-b-f})}};var d=a.fn.affix;a.fn.affix=b,a.fn.affix.Constructor=c,a.fn.affix.noConflict=function(){return a.fn.affix=d,this},a(window).on("load",function(){a('[data-spy="affix"]').each(function(){var c=a(this),d=c.data();d.offset=d.offset||{},null!=d.offsetBottom&&(d.offset.bottom=d.offsetBottom),null!=d.offsetTop&&(d.offset.top=d.offsetTop),b.call(c,d)})})}(jQuery); \ No newline at end of file diff --git a/resource/web/js/c3.LICENSE b/hal-core/resources/web/js/lib/c3.LICENSE old mode 100755 new mode 100644 similarity index 100% rename from resource/web/js/c3.LICENSE rename to hal-core/resources/web/js/lib/c3.LICENSE diff --git a/hal-core/resources/web/js/lib/c3.LICENSE.txt b/hal-core/resources/web/js/lib/c3.LICENSE.txt new file mode 100644 index 00000000..29ce9cb0 --- /dev/null +++ b/hal-core/resources/web/js/lib/c3.LICENSE.txt @@ -0,0 +1,20 @@ +The MIT License (MIT) + +Copyright (c) 2013 Masayuki Tanaka + +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. diff --git a/resource/web/js/c3.js b/hal-core/resources/web/js/lib/c3.js old mode 100755 new mode 100644 similarity index 100% rename from resource/web/js/c3.js rename to hal-core/resources/web/js/lib/c3.js diff --git a/resource/web/js/c3.min.js b/hal-core/resources/web/js/lib/c3.min.js old mode 100755 new mode 100644 similarity index 100% rename from resource/web/js/c3.min.js rename to hal-core/resources/web/js/lib/c3.min.js diff --git a/hal-core/resources/web/js/lib/d3.LICENSE b/hal-core/resources/web/js/lib/d3.LICENSE new file mode 100644 index 00000000..b0145150 --- /dev/null +++ b/hal-core/resources/web/js/lib/d3.LICENSE @@ -0,0 +1,13 @@ +Copyright 2010-2021 Mike Bostock + +Permission to use, copy, modify, and/or distribute this software for any purpose +with or without fee is hereby granted, provided that the above copyright notice +and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH +REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, +INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS +OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER +TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF +THIS SOFTWARE. diff --git a/hal-core/resources/web/js/lib/d3.LICENSE.txt b/hal-core/resources/web/js/lib/d3.LICENSE.txt new file mode 100644 index 00000000..b0145150 --- /dev/null +++ b/hal-core/resources/web/js/lib/d3.LICENSE.txt @@ -0,0 +1,13 @@ +Copyright 2010-2021 Mike Bostock + +Permission to use, copy, modify, and/or distribute this software for any purpose +with or without fee is hereby granted, provided that the above copyright notice +and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH +REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, +INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS +OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER +TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF +THIS SOFTWARE. diff --git a/resource/web/js/d3.js b/hal-core/resources/web/js/lib/d3.js old mode 100755 new mode 100644 similarity index 100% rename from resource/web/js/d3.js rename to hal-core/resources/web/js/lib/d3.js diff --git a/hal-core/resources/web/js/lib/force-graph.LICENSE.txt b/hal-core/resources/web/js/lib/force-graph.LICENSE.txt new file mode 100644 index 00000000..a36ddd4f --- /dev/null +++ b/hal-core/resources/web/js/lib/force-graph.LICENSE.txt @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2018 Vasco Asturiano + +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. diff --git a/hal-core/resources/web/js/lib/force-graph.js b/hal-core/resources/web/js/lib/force-graph.js new file mode 100644 index 00000000..13d6e200 --- /dev/null +++ b/hal-core/resources/web/js/lib/force-graph.js @@ -0,0 +1,12201 @@ +// Version 1.43.4 force-graph - https://github.com/vasturiano/force-graph +(function (global, factory) { + typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() : + typeof define === 'function' && define.amd ? define(factory) : + (global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.ForceGraph = factory()); +})(this, (function () { 'use strict'; + + function styleInject(css, ref) { + if ( ref === void 0 ) ref = {}; + var insertAt = ref.insertAt; + + if (!css || typeof document === 'undefined') { return; } + + var head = document.head || document.getElementsByTagName('head')[0]; + var style = document.createElement('style'); + style.type = 'text/css'; + + if (insertAt === 'top') { + if (head.firstChild) { + head.insertBefore(style, head.firstChild); + } else { + head.appendChild(style); + } + } else { + head.appendChild(style); + } + + if (style.styleSheet) { + style.styleSheet.cssText = css; + } else { + style.appendChild(document.createTextNode(css)); + } + } + + var css_248z = ".force-graph-container canvas {\n display: block;\n user-select: none;\n outline: none;\n -webkit-tap-highlight-color: transparent;\n}\n\n.force-graph-container .graph-tooltip {\n position: absolute;\n top: 0;\n font-family: sans-serif;\n font-size: 16px;\n padding: 4px;\n border-radius: 3px;\n color: #eee;\n background: rgba(0,0,0,0.65);\n visibility: hidden; /* by default */\n}\n\n.force-graph-container .clickable {\n cursor: pointer;\n}\n\n.force-graph-container .grabbable {\n cursor: move;\n cursor: grab;\n cursor: -moz-grab;\n cursor: -webkit-grab;\n}\n\n.force-graph-container .grabbable:active {\n cursor: grabbing;\n cursor: -moz-grabbing;\n cursor: -webkit-grabbing;\n}\n"; + styleInject(css_248z); + + function _iterableToArrayLimit$2(arr, i) { + var _i = null == arr ? null : "undefined" != typeof Symbol && arr[Symbol.iterator] || arr["@@iterator"]; + if (null != _i) { + var _s, + _e, + _x, + _r, + _arr = [], + _n = !0, + _d = !1; + try { + if (_x = (_i = _i.call(arr)).next, 0 === i) { + if (Object(_i) !== _i) return; + _n = !1; + } else for (; !(_n = (_s = _x.call(_i)).done) && (_arr.push(_s.value), _arr.length !== i); _n = !0); + } catch (err) { + _d = !0, _e = err; + } finally { + try { + if (!_n && null != _i.return && (_r = _i.return(), Object(_r) !== _r)) return; + } finally { + if (_d) throw _e; + } + } + return _arr; + } + } + function ownKeys(object, enumerableOnly) { + var keys = Object.keys(object); + if (Object.getOwnPropertySymbols) { + var symbols = Object.getOwnPropertySymbols(object); + enumerableOnly && (symbols = symbols.filter(function (sym) { + return Object.getOwnPropertyDescriptor(object, sym).enumerable; + })), keys.push.apply(keys, symbols); + } + return keys; + } + function _objectSpread2(target) { + for (var i = 1; i < arguments.length; i++) { + var source = null != arguments[i] ? arguments[i] : {}; + i % 2 ? ownKeys(Object(source), !0).forEach(function (key) { + _defineProperty(target, key, source[key]); + }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) { + Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); + }); + } + return target; + } + function _typeof$1(obj) { + "@babel/helpers - typeof"; + + return _typeof$1 = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (obj) { + return typeof obj; + } : function (obj) { + return obj && "function" == typeof Symbol && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; + }, _typeof$1(obj); + } + function _defineProperty(obj, key, value) { + key = _toPropertyKey$3(key); + if (key in obj) { + Object.defineProperty(obj, key, { + value: value, + enumerable: true, + configurable: true, + writable: true + }); + } else { + obj[key] = value; + } + return obj; + } + function _setPrototypeOf(o, p) { + _setPrototypeOf = Object.setPrototypeOf ? Object.setPrototypeOf.bind() : function _setPrototypeOf(o, p) { + o.__proto__ = p; + return o; + }; + return _setPrototypeOf(o, p); + } + function _isNativeReflectConstruct() { + if (typeof Reflect === "undefined" || !Reflect.construct) return false; + if (Reflect.construct.sham) return false; + if (typeof Proxy === "function") return true; + try { + Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {})); + return true; + } catch (e) { + return false; + } + } + function _construct(Parent, args, Class) { + if (_isNativeReflectConstruct()) { + _construct = Reflect.construct.bind(); + } else { + _construct = function _construct(Parent, args, Class) { + var a = [null]; + a.push.apply(a, args); + var Constructor = Function.bind.apply(Parent, a); + var instance = new Constructor(); + if (Class) _setPrototypeOf(instance, Class.prototype); + return instance; + }; + } + return _construct.apply(null, arguments); + } + function _slicedToArray$2(arr, i) { + return _arrayWithHoles$2(arr) || _iterableToArrayLimit$2(arr, i) || _unsupportedIterableToArray$3(arr, i) || _nonIterableRest$2(); + } + function _toConsumableArray$2(arr) { + return _arrayWithoutHoles$2(arr) || _iterableToArray$2(arr) || _unsupportedIterableToArray$3(arr) || _nonIterableSpread$2(); + } + function _arrayWithoutHoles$2(arr) { + if (Array.isArray(arr)) return _arrayLikeToArray$3(arr); + } + function _arrayWithHoles$2(arr) { + if (Array.isArray(arr)) return arr; + } + function _iterableToArray$2(iter) { + if (typeof Symbol !== "undefined" && iter[Symbol.iterator] != null || iter["@@iterator"] != null) return Array.from(iter); + } + function _unsupportedIterableToArray$3(o, minLen) { + if (!o) return; + if (typeof o === "string") return _arrayLikeToArray$3(o, minLen); + var n = Object.prototype.toString.call(o).slice(8, -1); + if (n === "Object" && o.constructor) n = o.constructor.name; + if (n === "Map" || n === "Set") return Array.from(o); + if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray$3(o, minLen); + } + function _arrayLikeToArray$3(arr, len) { + if (len == null || len > arr.length) len = arr.length; + for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i]; + return arr2; + } + function _nonIterableSpread$2() { + throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); + } + function _nonIterableRest$2() { + throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); + } + function _toPrimitive$3(input, hint) { + if (typeof input !== "object" || input === null) return input; + var prim = input[Symbol.toPrimitive]; + if (prim !== undefined) { + var res = prim.call(input, hint || "default"); + if (typeof res !== "object") return res; + throw new TypeError("@@toPrimitive must return a primitive value."); + } + return (hint === "string" ? String : Number)(input); + } + function _toPropertyKey$3(arg) { + var key = _toPrimitive$3(arg, "string"); + return typeof key === "symbol" ? key : String(key); + } + + var xhtml = "http://www.w3.org/1999/xhtml"; + + var namespaces = { + svg: "http://www.w3.org/2000/svg", + xhtml: xhtml, + xlink: "http://www.w3.org/1999/xlink", + xml: "http://www.w3.org/XML/1998/namespace", + xmlns: "http://www.w3.org/2000/xmlns/" + }; + + function namespace(name) { + var prefix = name += "", i = prefix.indexOf(":"); + if (i >= 0 && (prefix = name.slice(0, i)) !== "xmlns") name = name.slice(i + 1); + return namespaces.hasOwnProperty(prefix) ? {space: namespaces[prefix], local: name} : name; // eslint-disable-line no-prototype-builtins + } + + function creatorInherit(name) { + return function() { + var document = this.ownerDocument, + uri = this.namespaceURI; + return uri === xhtml && document.documentElement.namespaceURI === xhtml + ? document.createElement(name) + : document.createElementNS(uri, name); + }; + } + + function creatorFixed(fullname) { + return function() { + return this.ownerDocument.createElementNS(fullname.space, fullname.local); + }; + } + + function creator(name) { + var fullname = namespace(name); + return (fullname.local + ? creatorFixed + : creatorInherit)(fullname); + } + + function none() {} + + function selector(selector) { + return selector == null ? none : function() { + return this.querySelector(selector); + }; + } + + function selection_select(select) { + if (typeof select !== "function") select = selector(select); + + for (var groups = this._groups, m = groups.length, subgroups = new Array(m), j = 0; j < m; ++j) { + for (var group = groups[j], n = group.length, subgroup = subgroups[j] = new Array(n), node, subnode, i = 0; i < n; ++i) { + if ((node = group[i]) && (subnode = select.call(node, node.__data__, i, group))) { + if ("__data__" in node) subnode.__data__ = node.__data__; + subgroup[i] = subnode; + } + } + } + + return new Selection$1(subgroups, this._parents); + } + + // Given something array like (or null), returns something that is strictly an + // array. This is used to ensure that array-like objects passed to d3.selectAll + // or selection.selectAll are converted into proper arrays when creating a + // selection; we don’t ever want to create a selection backed by a live + // HTMLCollection or NodeList. However, note that selection.selectAll will use a + // static NodeList as a group, since it safely derived from querySelectorAll. + function array(x) { + return x == null ? [] : Array.isArray(x) ? x : Array.from(x); + } + + function empty() { + return []; + } + + function selectorAll(selector) { + return selector == null ? empty : function() { + return this.querySelectorAll(selector); + }; + } + + function arrayAll(select) { + return function() { + return array(select.apply(this, arguments)); + }; + } + + function selection_selectAll(select) { + if (typeof select === "function") select = arrayAll(select); + else select = selectorAll(select); + + for (var groups = this._groups, m = groups.length, subgroups = [], parents = [], j = 0; j < m; ++j) { + for (var group = groups[j], n = group.length, node, i = 0; i < n; ++i) { + if (node = group[i]) { + subgroups.push(select.call(node, node.__data__, i, group)); + parents.push(node); + } + } + } + + return new Selection$1(subgroups, parents); + } + + function matcher(selector) { + return function() { + return this.matches(selector); + }; + } + + function childMatcher(selector) { + return function(node) { + return node.matches(selector); + }; + } + + var find$1 = Array.prototype.find; + + function childFind(match) { + return function() { + return find$1.call(this.children, match); + }; + } + + function childFirst() { + return this.firstElementChild; + } + + function selection_selectChild(match) { + return this.select(match == null ? childFirst + : childFind(typeof match === "function" ? match : childMatcher(match))); + } + + var filter = Array.prototype.filter; + + function children() { + return Array.from(this.children); + } + + function childrenFilter(match) { + return function() { + return filter.call(this.children, match); + }; + } + + function selection_selectChildren(match) { + return this.selectAll(match == null ? children + : childrenFilter(typeof match === "function" ? match : childMatcher(match))); + } + + function selection_filter(match) { + if (typeof match !== "function") match = matcher(match); + + for (var groups = this._groups, m = groups.length, subgroups = new Array(m), j = 0; j < m; ++j) { + for (var group = groups[j], n = group.length, subgroup = subgroups[j] = [], node, i = 0; i < n; ++i) { + if ((node = group[i]) && match.call(node, node.__data__, i, group)) { + subgroup.push(node); + } + } + } + + return new Selection$1(subgroups, this._parents); + } + + function sparse(update) { + return new Array(update.length); + } + + function selection_enter() { + return new Selection$1(this._enter || this._groups.map(sparse), this._parents); + } + + function EnterNode(parent, datum) { + this.ownerDocument = parent.ownerDocument; + this.namespaceURI = parent.namespaceURI; + this._next = null; + this._parent = parent; + this.__data__ = datum; + } + + EnterNode.prototype = { + constructor: EnterNode, + appendChild: function(child) { return this._parent.insertBefore(child, this._next); }, + insertBefore: function(child, next) { return this._parent.insertBefore(child, next); }, + querySelector: function(selector) { return this._parent.querySelector(selector); }, + querySelectorAll: function(selector) { return this._parent.querySelectorAll(selector); } + }; + + function constant$4(x) { + return function() { + return x; + }; + } + + function bindIndex(parent, group, enter, update, exit, data) { + var i = 0, + node, + groupLength = group.length, + dataLength = data.length; + + // Put any non-null nodes that fit into update. + // Put any null nodes into enter. + // Put any remaining data into enter. + for (; i < dataLength; ++i) { + if (node = group[i]) { + node.__data__ = data[i]; + update[i] = node; + } else { + enter[i] = new EnterNode(parent, data[i]); + } + } + + // Put any non-null nodes that don’t fit into exit. + for (; i < groupLength; ++i) { + if (node = group[i]) { + exit[i] = node; + } + } + } + + function bindKey(parent, group, enter, update, exit, data, key) { + var i, + node, + nodeByKeyValue = new Map, + groupLength = group.length, + dataLength = data.length, + keyValues = new Array(groupLength), + keyValue; + + // Compute the key for each node. + // If multiple nodes have the same key, the duplicates are added to exit. + for (i = 0; i < groupLength; ++i) { + if (node = group[i]) { + keyValues[i] = keyValue = key.call(node, node.__data__, i, group) + ""; + if (nodeByKeyValue.has(keyValue)) { + exit[i] = node; + } else { + nodeByKeyValue.set(keyValue, node); + } + } + } + + // Compute the key for each datum. + // If there a node associated with this key, join and add it to update. + // If there is not (or the key is a duplicate), add it to enter. + for (i = 0; i < dataLength; ++i) { + keyValue = key.call(parent, data[i], i, data) + ""; + if (node = nodeByKeyValue.get(keyValue)) { + update[i] = node; + node.__data__ = data[i]; + nodeByKeyValue.delete(keyValue); + } else { + enter[i] = new EnterNode(parent, data[i]); + } + } + + // Add any remaining nodes that were not bound to data to exit. + for (i = 0; i < groupLength; ++i) { + if ((node = group[i]) && (nodeByKeyValue.get(keyValues[i]) === node)) { + exit[i] = node; + } + } + } + + function datum(node) { + return node.__data__; + } + + function selection_data(value, key) { + if (!arguments.length) return Array.from(this, datum); + + var bind = key ? bindKey : bindIndex, + parents = this._parents, + groups = this._groups; + + if (typeof value !== "function") value = constant$4(value); + + for (var m = groups.length, update = new Array(m), enter = new Array(m), exit = new Array(m), j = 0; j < m; ++j) { + var parent = parents[j], + group = groups[j], + groupLength = group.length, + data = arraylike(value.call(parent, parent && parent.__data__, j, parents)), + dataLength = data.length, + enterGroup = enter[j] = new Array(dataLength), + updateGroup = update[j] = new Array(dataLength), + exitGroup = exit[j] = new Array(groupLength); + + bind(parent, group, enterGroup, updateGroup, exitGroup, data, key); + + // Now connect the enter nodes to their following update node, such that + // appendChild can insert the materialized enter node before this node, + // rather than at the end of the parent node. + for (var i0 = 0, i1 = 0, previous, next; i0 < dataLength; ++i0) { + if (previous = enterGroup[i0]) { + if (i0 >= i1) i1 = i0 + 1; + while (!(next = updateGroup[i1]) && ++i1 < dataLength); + previous._next = next || null; + } + } + } + + update = new Selection$1(update, parents); + update._enter = enter; + update._exit = exit; + return update; + } + + // Given some data, this returns an array-like view of it: an object that + // exposes a length property and allows numeric indexing. Note that unlike + // selectAll, this isn’t worried about “live†collections because the resulting + // array will only be used briefly while data is being bound. (It is possible to + // cause the data to change while iterating by using a key function, but please + // don’t; we’d rather avoid a gratuitous copy.) + function arraylike(data) { + return typeof data === "object" && "length" in data + ? data // Array, TypedArray, NodeList, array-like + : Array.from(data); // Map, Set, iterable, string, or anything else + } + + function selection_exit() { + return new Selection$1(this._exit || this._groups.map(sparse), this._parents); + } + + function selection_join(onenter, onupdate, onexit) { + var enter = this.enter(), update = this, exit = this.exit(); + if (typeof onenter === "function") { + enter = onenter(enter); + if (enter) enter = enter.selection(); + } else { + enter = enter.append(onenter + ""); + } + if (onupdate != null) { + update = onupdate(update); + if (update) update = update.selection(); + } + if (onexit == null) exit.remove(); else onexit(exit); + return enter && update ? enter.merge(update).order() : update; + } + + function selection_merge(context) { + var selection = context.selection ? context.selection() : context; + + for (var groups0 = this._groups, groups1 = selection._groups, m0 = groups0.length, m1 = groups1.length, m = Math.min(m0, m1), merges = new Array(m0), j = 0; j < m; ++j) { + for (var group0 = groups0[j], group1 = groups1[j], n = group0.length, merge = merges[j] = new Array(n), node, i = 0; i < n; ++i) { + if (node = group0[i] || group1[i]) { + merge[i] = node; + } + } + } + + for (; j < m0; ++j) { + merges[j] = groups0[j]; + } + + return new Selection$1(merges, this._parents); + } + + function selection_order() { + + for (var groups = this._groups, j = -1, m = groups.length; ++j < m;) { + for (var group = groups[j], i = group.length - 1, next = group[i], node; --i >= 0;) { + if (node = group[i]) { + if (next && node.compareDocumentPosition(next) ^ 4) next.parentNode.insertBefore(node, next); + next = node; + } + } + } + + return this; + } + + function selection_sort(compare) { + if (!compare) compare = ascending; + + function compareNode(a, b) { + return a && b ? compare(a.__data__, b.__data__) : !a - !b; + } + + for (var groups = this._groups, m = groups.length, sortgroups = new Array(m), j = 0; j < m; ++j) { + for (var group = groups[j], n = group.length, sortgroup = sortgroups[j] = new Array(n), node, i = 0; i < n; ++i) { + if (node = group[i]) { + sortgroup[i] = node; + } + } + sortgroup.sort(compareNode); + } + + return new Selection$1(sortgroups, this._parents).order(); + } + + function ascending(a, b) { + return a < b ? -1 : a > b ? 1 : a >= b ? 0 : NaN; + } + + function selection_call() { + var callback = arguments[0]; + arguments[0] = this; + callback.apply(null, arguments); + return this; + } + + function selection_nodes() { + return Array.from(this); + } + + function selection_node() { + + for (var groups = this._groups, j = 0, m = groups.length; j < m; ++j) { + for (var group = groups[j], i = 0, n = group.length; i < n; ++i) { + var node = group[i]; + if (node) return node; + } + } + + return null; + } + + function selection_size() { + let size = 0; + for (const node of this) ++size; // eslint-disable-line no-unused-vars + return size; + } + + function selection_empty() { + return !this.node(); + } + + function selection_each(callback) { + + for (var groups = this._groups, j = 0, m = groups.length; j < m; ++j) { + for (var group = groups[j], i = 0, n = group.length, node; i < n; ++i) { + if (node = group[i]) callback.call(node, node.__data__, i, group); + } + } + + return this; + } + + function attrRemove$1(name) { + return function() { + this.removeAttribute(name); + }; + } + + function attrRemoveNS$1(fullname) { + return function() { + this.removeAttributeNS(fullname.space, fullname.local); + }; + } + + function attrConstant$1(name, value) { + return function() { + this.setAttribute(name, value); + }; + } + + function attrConstantNS$1(fullname, value) { + return function() { + this.setAttributeNS(fullname.space, fullname.local, value); + }; + } + + function attrFunction$1(name, value) { + return function() { + var v = value.apply(this, arguments); + if (v == null) this.removeAttribute(name); + else this.setAttribute(name, v); + }; + } + + function attrFunctionNS$1(fullname, value) { + return function() { + var v = value.apply(this, arguments); + if (v == null) this.removeAttributeNS(fullname.space, fullname.local); + else this.setAttributeNS(fullname.space, fullname.local, v); + }; + } + + function selection_attr(name, value) { + var fullname = namespace(name); + + if (arguments.length < 2) { + var node = this.node(); + return fullname.local + ? node.getAttributeNS(fullname.space, fullname.local) + : node.getAttribute(fullname); + } + + return this.each((value == null + ? (fullname.local ? attrRemoveNS$1 : attrRemove$1) : (typeof value === "function" + ? (fullname.local ? attrFunctionNS$1 : attrFunction$1) + : (fullname.local ? attrConstantNS$1 : attrConstant$1)))(fullname, value)); + } + + function defaultView(node) { + return (node.ownerDocument && node.ownerDocument.defaultView) // node is a Node + || (node.document && node) // node is a Window + || node.defaultView; // node is a Document + } + + function styleRemove$1(name) { + return function() { + this.style.removeProperty(name); + }; + } + + function styleConstant$1(name, value, priority) { + return function() { + this.style.setProperty(name, value, priority); + }; + } + + function styleFunction$1(name, value, priority) { + return function() { + var v = value.apply(this, arguments); + if (v == null) this.style.removeProperty(name); + else this.style.setProperty(name, v, priority); + }; + } + + function selection_style(name, value, priority) { + return arguments.length > 1 + ? this.each((value == null + ? styleRemove$1 : typeof value === "function" + ? styleFunction$1 + : styleConstant$1)(name, value, priority == null ? "" : priority)) + : styleValue(this.node(), name); + } + + function styleValue(node, name) { + return node.style.getPropertyValue(name) + || defaultView(node).getComputedStyle(node, null).getPropertyValue(name); + } + + function propertyRemove(name) { + return function() { + delete this[name]; + }; + } + + function propertyConstant(name, value) { + return function() { + this[name] = value; + }; + } + + function propertyFunction(name, value) { + return function() { + var v = value.apply(this, arguments); + if (v == null) delete this[name]; + else this[name] = v; + }; + } + + function selection_property(name, value) { + return arguments.length > 1 + ? this.each((value == null + ? propertyRemove : typeof value === "function" + ? propertyFunction + : propertyConstant)(name, value)) + : this.node()[name]; + } + + function classArray(string) { + return string.trim().split(/^|\s+/); + } + + function classList(node) { + return node.classList || new ClassList(node); + } + + function ClassList(node) { + this._node = node; + this._names = classArray(node.getAttribute("class") || ""); + } + + ClassList.prototype = { + add: function(name) { + var i = this._names.indexOf(name); + if (i < 0) { + this._names.push(name); + this._node.setAttribute("class", this._names.join(" ")); + } + }, + remove: function(name) { + var i = this._names.indexOf(name); + if (i >= 0) { + this._names.splice(i, 1); + this._node.setAttribute("class", this._names.join(" ")); + } + }, + contains: function(name) { + return this._names.indexOf(name) >= 0; + } + }; + + function classedAdd(node, names) { + var list = classList(node), i = -1, n = names.length; + while (++i < n) list.add(names[i]); + } + + function classedRemove(node, names) { + var list = classList(node), i = -1, n = names.length; + while (++i < n) list.remove(names[i]); + } + + function classedTrue(names) { + return function() { + classedAdd(this, names); + }; + } + + function classedFalse(names) { + return function() { + classedRemove(this, names); + }; + } + + function classedFunction(names, value) { + return function() { + (value.apply(this, arguments) ? classedAdd : classedRemove)(this, names); + }; + } + + function selection_classed(name, value) { + var names = classArray(name + ""); + + if (arguments.length < 2) { + var list = classList(this.node()), i = -1, n = names.length; + while (++i < n) if (!list.contains(names[i])) return false; + return true; + } + + return this.each((typeof value === "function" + ? classedFunction : value + ? classedTrue + : classedFalse)(names, value)); + } + + function textRemove() { + this.textContent = ""; + } + + function textConstant$1(value) { + return function() { + this.textContent = value; + }; + } + + function textFunction$1(value) { + return function() { + var v = value.apply(this, arguments); + this.textContent = v == null ? "" : v; + }; + } + + function selection_text(value) { + return arguments.length + ? this.each(value == null + ? textRemove : (typeof value === "function" + ? textFunction$1 + : textConstant$1)(value)) + : this.node().textContent; + } + + function htmlRemove() { + this.innerHTML = ""; + } + + function htmlConstant(value) { + return function() { + this.innerHTML = value; + }; + } + + function htmlFunction(value) { + return function() { + var v = value.apply(this, arguments); + this.innerHTML = v == null ? "" : v; + }; + } + + function selection_html(value) { + return arguments.length + ? this.each(value == null + ? htmlRemove : (typeof value === "function" + ? htmlFunction + : htmlConstant)(value)) + : this.node().innerHTML; + } + + function raise() { + if (this.nextSibling) this.parentNode.appendChild(this); + } + + function selection_raise() { + return this.each(raise); + } + + function lower() { + if (this.previousSibling) this.parentNode.insertBefore(this, this.parentNode.firstChild); + } + + function selection_lower() { + return this.each(lower); + } + + function selection_append(name) { + var create = typeof name === "function" ? name : creator(name); + return this.select(function() { + return this.appendChild(create.apply(this, arguments)); + }); + } + + function constantNull() { + return null; + } + + function selection_insert(name, before) { + var create = typeof name === "function" ? name : creator(name), + select = before == null ? constantNull : typeof before === "function" ? before : selector(before); + return this.select(function() { + return this.insertBefore(create.apply(this, arguments), select.apply(this, arguments) || null); + }); + } + + function remove() { + var parent = this.parentNode; + if (parent) parent.removeChild(this); + } + + function selection_remove() { + return this.each(remove); + } + + function selection_cloneShallow() { + var clone = this.cloneNode(false), parent = this.parentNode; + return parent ? parent.insertBefore(clone, this.nextSibling) : clone; + } + + function selection_cloneDeep() { + var clone = this.cloneNode(true), parent = this.parentNode; + return parent ? parent.insertBefore(clone, this.nextSibling) : clone; + } + + function selection_clone(deep) { + return this.select(deep ? selection_cloneDeep : selection_cloneShallow); + } + + function selection_datum(value) { + return arguments.length + ? this.property("__data__", value) + : this.node().__data__; + } + + function contextListener(listener) { + return function(event) { + listener.call(this, event, this.__data__); + }; + } + + function parseTypenames$1(typenames) { + return typenames.trim().split(/^|\s+/).map(function(t) { + var name = "", i = t.indexOf("."); + if (i >= 0) name = t.slice(i + 1), t = t.slice(0, i); + return {type: t, name: name}; + }); + } + + function onRemove(typename) { + return function() { + var on = this.__on; + if (!on) return; + for (var j = 0, i = -1, m = on.length, o; j < m; ++j) { + if (o = on[j], (!typename.type || o.type === typename.type) && o.name === typename.name) { + this.removeEventListener(o.type, o.listener, o.options); + } else { + on[++i] = o; + } + } + if (++i) on.length = i; + else delete this.__on; + }; + } + + function onAdd(typename, value, options) { + return function() { + var on = this.__on, o, listener = contextListener(value); + if (on) for (var j = 0, m = on.length; j < m; ++j) { + if ((o = on[j]).type === typename.type && o.name === typename.name) { + this.removeEventListener(o.type, o.listener, o.options); + this.addEventListener(o.type, o.listener = listener, o.options = options); + o.value = value; + return; + } + } + this.addEventListener(typename.type, listener, options); + o = {type: typename.type, name: typename.name, value: value, listener: listener, options: options}; + if (!on) this.__on = [o]; + else on.push(o); + }; + } + + function selection_on(typename, value, options) { + var typenames = parseTypenames$1(typename + ""), i, n = typenames.length, t; + + if (arguments.length < 2) { + var on = this.node().__on; + if (on) for (var j = 0, m = on.length, o; j < m; ++j) { + for (i = 0, o = on[j]; i < n; ++i) { + if ((t = typenames[i]).type === o.type && t.name === o.name) { + return o.value; + } + } + } + return; + } + + on = value ? onAdd : onRemove; + for (i = 0; i < n; ++i) this.each(on(typenames[i], value, options)); + return this; + } + + function dispatchEvent(node, type, params) { + var window = defaultView(node), + event = window.CustomEvent; + + if (typeof event === "function") { + event = new event(type, params); + } else { + event = window.document.createEvent("Event"); + if (params) event.initEvent(type, params.bubbles, params.cancelable), event.detail = params.detail; + else event.initEvent(type, false, false); + } + + node.dispatchEvent(event); + } + + function dispatchConstant(type, params) { + return function() { + return dispatchEvent(this, type, params); + }; + } + + function dispatchFunction(type, params) { + return function() { + return dispatchEvent(this, type, params.apply(this, arguments)); + }; + } + + function selection_dispatch(type, params) { + return this.each((typeof params === "function" + ? dispatchFunction + : dispatchConstant)(type, params)); + } + + function* selection_iterator() { + for (var groups = this._groups, j = 0, m = groups.length; j < m; ++j) { + for (var group = groups[j], i = 0, n = group.length, node; i < n; ++i) { + if (node = group[i]) yield node; + } + } + } + + var root$2 = [null]; + + function Selection$1(groups, parents) { + this._groups = groups; + this._parents = parents; + } + + function selection() { + return new Selection$1([[document.documentElement]], root$2); + } + + function selection_selection() { + return this; + } + + Selection$1.prototype = selection.prototype = { + constructor: Selection$1, + select: selection_select, + selectAll: selection_selectAll, + selectChild: selection_selectChild, + selectChildren: selection_selectChildren, + filter: selection_filter, + data: selection_data, + enter: selection_enter, + exit: selection_exit, + join: selection_join, + merge: selection_merge, + selection: selection_selection, + order: selection_order, + sort: selection_sort, + call: selection_call, + nodes: selection_nodes, + node: selection_node, + size: selection_size, + empty: selection_empty, + each: selection_each, + attr: selection_attr, + style: selection_style, + property: selection_property, + classed: selection_classed, + text: selection_text, + html: selection_html, + raise: selection_raise, + lower: selection_lower, + append: selection_append, + insert: selection_insert, + remove: selection_remove, + clone: selection_clone, + datum: selection_datum, + on: selection_on, + dispatch: selection_dispatch, + [Symbol.iterator]: selection_iterator + }; + + function d3Select(selector) { + return typeof selector === "string" + ? new Selection$1([[document.querySelector(selector)]], [document.documentElement]) + : new Selection$1([[selector]], root$2); + } + + function sourceEvent(event) { + let sourceEvent; + while (sourceEvent = event.sourceEvent) event = sourceEvent; + return event; + } + + function pointer(event, node) { + event = sourceEvent(event); + if (node === undefined) node = event.currentTarget; + if (node) { + var svg = node.ownerSVGElement || node; + if (svg.createSVGPoint) { + var point = svg.createSVGPoint(); + point.x = event.clientX, point.y = event.clientY; + point = point.matrixTransform(node.getScreenCTM().inverse()); + return [point.x, point.y]; + } + if (node.getBoundingClientRect) { + var rect = node.getBoundingClientRect(); + return [event.clientX - rect.left - node.clientLeft, event.clientY - rect.top - node.clientTop]; + } + } + return [event.pageX, event.pageY]; + } + + var noop = {value: () => {}}; + + function dispatch() { + for (var i = 0, n = arguments.length, _ = {}, t; i < n; ++i) { + if (!(t = arguments[i] + "") || (t in _) || /[\s.]/.test(t)) throw new Error("illegal type: " + t); + _[t] = []; + } + return new Dispatch(_); + } + + function Dispatch(_) { + this._ = _; + } + + function parseTypenames(typenames, types) { + return typenames.trim().split(/^|\s+/).map(function(t) { + var name = "", i = t.indexOf("."); + if (i >= 0) name = t.slice(i + 1), t = t.slice(0, i); + if (t && !types.hasOwnProperty(t)) throw new Error("unknown type: " + t); + return {type: t, name: name}; + }); + } + + Dispatch.prototype = dispatch.prototype = { + constructor: Dispatch, + on: function(typename, callback) { + var _ = this._, + T = parseTypenames(typename + "", _), + t, + i = -1, + n = T.length; + + // If no callback was specified, return the callback of the given type and name. + if (arguments.length < 2) { + while (++i < n) if ((t = (typename = T[i]).type) && (t = get$1(_[t], typename.name))) return t; + return; + } + + // If a type was specified, set the callback for the given type and name. + // Otherwise, if a null callback was specified, remove callbacks of the given name. + if (callback != null && typeof callback !== "function") throw new Error("invalid callback: " + callback); + while (++i < n) { + if (t = (typename = T[i]).type) _[t] = set$1(_[t], typename.name, callback); + else if (callback == null) for (t in _) _[t] = set$1(_[t], typename.name, null); + } + + return this; + }, + copy: function() { + var copy = {}, _ = this._; + for (var t in _) copy[t] = _[t].slice(); + return new Dispatch(copy); + }, + call: function(type, that) { + if ((n = arguments.length - 2) > 0) for (var args = new Array(n), i = 0, n, t; i < n; ++i) args[i] = arguments[i + 2]; + if (!this._.hasOwnProperty(type)) throw new Error("unknown type: " + type); + for (t = this._[type], i = 0, n = t.length; i < n; ++i) t[i].value.apply(that, args); + }, + apply: function(type, that, args) { + if (!this._.hasOwnProperty(type)) throw new Error("unknown type: " + type); + for (var t = this._[type], i = 0, n = t.length; i < n; ++i) t[i].value.apply(that, args); + } + }; + + function get$1(type, name) { + for (var i = 0, n = type.length, c; i < n; ++i) { + if ((c = type[i]).name === name) { + return c.value; + } + } + } + + function set$1(type, name, callback) { + for (var i = 0, n = type.length; i < n; ++i) { + if (type[i].name === name) { + type[i] = noop, type = type.slice(0, i).concat(type.slice(i + 1)); + break; + } + } + if (callback != null) type.push({name: name, value: callback}); + return type; + } + + // These are typically used in conjunction with noevent to ensure that we can + // preventDefault on the event. + const nonpassive = {passive: false}; + const nonpassivecapture = {capture: true, passive: false}; + + function nopropagation$1(event) { + event.stopImmediatePropagation(); + } + + function noevent$1(event) { + event.preventDefault(); + event.stopImmediatePropagation(); + } + + function dragDisable(view) { + var root = view.document.documentElement, + selection = d3Select(view).on("dragstart.drag", noevent$1, nonpassivecapture); + if ("onselectstart" in root) { + selection.on("selectstart.drag", noevent$1, nonpassivecapture); + } else { + root.__noselect = root.style.MozUserSelect; + root.style.MozUserSelect = "none"; + } + } + + function yesdrag(view, noclick) { + var root = view.document.documentElement, + selection = d3Select(view).on("dragstart.drag", null); + if (noclick) { + selection.on("click.drag", noevent$1, nonpassivecapture); + setTimeout(function() { selection.on("click.drag", null); }, 0); + } + if ("onselectstart" in root) { + selection.on("selectstart.drag", null); + } else { + root.style.MozUserSelect = root.__noselect; + delete root.__noselect; + } + } + + var constant$3 = x => () => x; + + function DragEvent(type, { + sourceEvent, + subject, + target, + identifier, + active, + x, y, dx, dy, + dispatch + }) { + Object.defineProperties(this, { + type: {value: type, enumerable: true, configurable: true}, + sourceEvent: {value: sourceEvent, enumerable: true, configurable: true}, + subject: {value: subject, enumerable: true, configurable: true}, + target: {value: target, enumerable: true, configurable: true}, + identifier: {value: identifier, enumerable: true, configurable: true}, + active: {value: active, enumerable: true, configurable: true}, + x: {value: x, enumerable: true, configurable: true}, + y: {value: y, enumerable: true, configurable: true}, + dx: {value: dx, enumerable: true, configurable: true}, + dy: {value: dy, enumerable: true, configurable: true}, + _: {value: dispatch} + }); + } + + DragEvent.prototype.on = function() { + var value = this._.on.apply(this._, arguments); + return value === this._ ? this : value; + }; + + // Ignore right-click, since that should open the context menu. + function defaultFilter$1(event) { + return !event.ctrlKey && !event.button; + } + + function defaultContainer() { + return this.parentNode; + } + + function defaultSubject(event, d) { + return d == null ? {x: event.x, y: event.y} : d; + } + + function defaultTouchable$1() { + return navigator.maxTouchPoints || ("ontouchstart" in this); + } + + function d3Drag() { + var filter = defaultFilter$1, + container = defaultContainer, + subject = defaultSubject, + touchable = defaultTouchable$1, + gestures = {}, + listeners = dispatch("start", "drag", "end"), + active = 0, + mousedownx, + mousedowny, + mousemoving, + touchending, + clickDistance2 = 0; + + function drag(selection) { + selection + .on("mousedown.drag", mousedowned) + .filter(touchable) + .on("touchstart.drag", touchstarted) + .on("touchmove.drag", touchmoved, nonpassive) + .on("touchend.drag touchcancel.drag", touchended) + .style("touch-action", "none") + .style("-webkit-tap-highlight-color", "rgba(0,0,0,0)"); + } + + function mousedowned(event, d) { + if (touchending || !filter.call(this, event, d)) return; + var gesture = beforestart(this, container.call(this, event, d), event, d, "mouse"); + if (!gesture) return; + d3Select(event.view) + .on("mousemove.drag", mousemoved, nonpassivecapture) + .on("mouseup.drag", mouseupped, nonpassivecapture); + dragDisable(event.view); + nopropagation$1(event); + mousemoving = false; + mousedownx = event.clientX; + mousedowny = event.clientY; + gesture("start", event); + } + + function mousemoved(event) { + noevent$1(event); + if (!mousemoving) { + var dx = event.clientX - mousedownx, dy = event.clientY - mousedowny; + mousemoving = dx * dx + dy * dy > clickDistance2; + } + gestures.mouse("drag", event); + } + + function mouseupped(event) { + d3Select(event.view).on("mousemove.drag mouseup.drag", null); + yesdrag(event.view, mousemoving); + noevent$1(event); + gestures.mouse("end", event); + } + + function touchstarted(event, d) { + if (!filter.call(this, event, d)) return; + var touches = event.changedTouches, + c = container.call(this, event, d), + n = touches.length, i, gesture; + + for (i = 0; i < n; ++i) { + if (gesture = beforestart(this, c, event, d, touches[i].identifier, touches[i])) { + nopropagation$1(event); + gesture("start", event, touches[i]); + } + } + } + + function touchmoved(event) { + var touches = event.changedTouches, + n = touches.length, i, gesture; + + for (i = 0; i < n; ++i) { + if (gesture = gestures[touches[i].identifier]) { + noevent$1(event); + gesture("drag", event, touches[i]); + } + } + } + + function touchended(event) { + var touches = event.changedTouches, + n = touches.length, i, gesture; + + if (touchending) clearTimeout(touchending); + touchending = setTimeout(function() { touchending = null; }, 500); // Ghost clicks are delayed! + for (i = 0; i < n; ++i) { + if (gesture = gestures[touches[i].identifier]) { + nopropagation$1(event); + gesture("end", event, touches[i]); + } + } + } + + function beforestart(that, container, event, d, identifier, touch) { + var dispatch = listeners.copy(), + p = pointer(touch || event, container), dx, dy, + s; + + if ((s = subject.call(that, new DragEvent("beforestart", { + sourceEvent: event, + target: drag, + identifier, + active, + x: p[0], + y: p[1], + dx: 0, + dy: 0, + dispatch + }), d)) == null) return; + + dx = s.x - p[0] || 0; + dy = s.y - p[1] || 0; + + return function gesture(type, event, touch) { + var p0 = p, n; + switch (type) { + case "start": gestures[identifier] = gesture, n = active++; break; + case "end": delete gestures[identifier], --active; // falls through + case "drag": p = pointer(touch || event, container), n = active; break; + } + dispatch.call( + type, + that, + new DragEvent(type, { + sourceEvent: event, + subject: s, + target: drag, + identifier, + active: n, + x: p[0] + dx, + y: p[1] + dy, + dx: p[0] - p0[0], + dy: p[1] - p0[1], + dispatch + }), + d + ); + }; + } + + drag.filter = function(_) { + return arguments.length ? (filter = typeof _ === "function" ? _ : constant$3(!!_), drag) : filter; + }; + + drag.container = function(_) { + return arguments.length ? (container = typeof _ === "function" ? _ : constant$3(_), drag) : container; + }; + + drag.subject = function(_) { + return arguments.length ? (subject = typeof _ === "function" ? _ : constant$3(_), drag) : subject; + }; + + drag.touchable = function(_) { + return arguments.length ? (touchable = typeof _ === "function" ? _ : constant$3(!!_), drag) : touchable; + }; + + drag.on = function() { + var value = listeners.on.apply(listeners, arguments); + return value === listeners ? drag : value; + }; + + drag.clickDistance = function(_) { + return arguments.length ? (clickDistance2 = (_ = +_) * _, drag) : Math.sqrt(clickDistance2); + }; + + return drag; + } + + function define(constructor, factory, prototype) { + constructor.prototype = factory.prototype = prototype; + prototype.constructor = constructor; + } + + function extend(parent, definition) { + var prototype = Object.create(parent.prototype); + for (var key in definition) prototype[key] = definition[key]; + return prototype; + } + + function Color() {} + + var darker = 0.7; + var brighter = 1 / darker; + + var reI = "\\s*([+-]?\\d+)\\s*", + reN = "\\s*([+-]?(?:\\d*\\.)?\\d+(?:[eE][+-]?\\d+)?)\\s*", + reP = "\\s*([+-]?(?:\\d*\\.)?\\d+(?:[eE][+-]?\\d+)?)%\\s*", + reHex = /^#([0-9a-f]{3,8})$/, + reRgbInteger = new RegExp(`^rgb\\(${reI},${reI},${reI}\\)$`), + reRgbPercent = new RegExp(`^rgb\\(${reP},${reP},${reP}\\)$`), + reRgbaInteger = new RegExp(`^rgba\\(${reI},${reI},${reI},${reN}\\)$`), + reRgbaPercent = new RegExp(`^rgba\\(${reP},${reP},${reP},${reN}\\)$`), + reHslPercent = new RegExp(`^hsl\\(${reN},${reP},${reP}\\)$`), + reHslaPercent = new RegExp(`^hsla\\(${reN},${reP},${reP},${reN}\\)$`); + + var named = { + aliceblue: 0xf0f8ff, + antiquewhite: 0xfaebd7, + aqua: 0x00ffff, + aquamarine: 0x7fffd4, + azure: 0xf0ffff, + beige: 0xf5f5dc, + bisque: 0xffe4c4, + black: 0x000000, + blanchedalmond: 0xffebcd, + blue: 0x0000ff, + blueviolet: 0x8a2be2, + brown: 0xa52a2a, + burlywood: 0xdeb887, + cadetblue: 0x5f9ea0, + chartreuse: 0x7fff00, + chocolate: 0xd2691e, + coral: 0xff7f50, + cornflowerblue: 0x6495ed, + cornsilk: 0xfff8dc, + crimson: 0xdc143c, + cyan: 0x00ffff, + darkblue: 0x00008b, + darkcyan: 0x008b8b, + darkgoldenrod: 0xb8860b, + darkgray: 0xa9a9a9, + darkgreen: 0x006400, + darkgrey: 0xa9a9a9, + darkkhaki: 0xbdb76b, + darkmagenta: 0x8b008b, + darkolivegreen: 0x556b2f, + darkorange: 0xff8c00, + darkorchid: 0x9932cc, + darkred: 0x8b0000, + darksalmon: 0xe9967a, + darkseagreen: 0x8fbc8f, + darkslateblue: 0x483d8b, + darkslategray: 0x2f4f4f, + darkslategrey: 0x2f4f4f, + darkturquoise: 0x00ced1, + darkviolet: 0x9400d3, + deeppink: 0xff1493, + deepskyblue: 0x00bfff, + dimgray: 0x696969, + dimgrey: 0x696969, + dodgerblue: 0x1e90ff, + firebrick: 0xb22222, + floralwhite: 0xfffaf0, + forestgreen: 0x228b22, + fuchsia: 0xff00ff, + gainsboro: 0xdcdcdc, + ghostwhite: 0xf8f8ff, + gold: 0xffd700, + goldenrod: 0xdaa520, + gray: 0x808080, + green: 0x008000, + greenyellow: 0xadff2f, + grey: 0x808080, + honeydew: 0xf0fff0, + hotpink: 0xff69b4, + indianred: 0xcd5c5c, + indigo: 0x4b0082, + ivory: 0xfffff0, + khaki: 0xf0e68c, + lavender: 0xe6e6fa, + lavenderblush: 0xfff0f5, + lawngreen: 0x7cfc00, + lemonchiffon: 0xfffacd, + lightblue: 0xadd8e6, + lightcoral: 0xf08080, + lightcyan: 0xe0ffff, + lightgoldenrodyellow: 0xfafad2, + lightgray: 0xd3d3d3, + lightgreen: 0x90ee90, + lightgrey: 0xd3d3d3, + lightpink: 0xffb6c1, + lightsalmon: 0xffa07a, + lightseagreen: 0x20b2aa, + lightskyblue: 0x87cefa, + lightslategray: 0x778899, + lightslategrey: 0x778899, + lightsteelblue: 0xb0c4de, + lightyellow: 0xffffe0, + lime: 0x00ff00, + limegreen: 0x32cd32, + linen: 0xfaf0e6, + magenta: 0xff00ff, + maroon: 0x800000, + mediumaquamarine: 0x66cdaa, + mediumblue: 0x0000cd, + mediumorchid: 0xba55d3, + mediumpurple: 0x9370db, + mediumseagreen: 0x3cb371, + mediumslateblue: 0x7b68ee, + mediumspringgreen: 0x00fa9a, + mediumturquoise: 0x48d1cc, + mediumvioletred: 0xc71585, + midnightblue: 0x191970, + mintcream: 0xf5fffa, + mistyrose: 0xffe4e1, + moccasin: 0xffe4b5, + navajowhite: 0xffdead, + navy: 0x000080, + oldlace: 0xfdf5e6, + olive: 0x808000, + olivedrab: 0x6b8e23, + orange: 0xffa500, + orangered: 0xff4500, + orchid: 0xda70d6, + palegoldenrod: 0xeee8aa, + palegreen: 0x98fb98, + paleturquoise: 0xafeeee, + palevioletred: 0xdb7093, + papayawhip: 0xffefd5, + peachpuff: 0xffdab9, + peru: 0xcd853f, + pink: 0xffc0cb, + plum: 0xdda0dd, + powderblue: 0xb0e0e6, + purple: 0x800080, + rebeccapurple: 0x663399, + red: 0xff0000, + rosybrown: 0xbc8f8f, + royalblue: 0x4169e1, + saddlebrown: 0x8b4513, + salmon: 0xfa8072, + sandybrown: 0xf4a460, + seagreen: 0x2e8b57, + seashell: 0xfff5ee, + sienna: 0xa0522d, + silver: 0xc0c0c0, + skyblue: 0x87ceeb, + slateblue: 0x6a5acd, + slategray: 0x708090, + slategrey: 0x708090, + snow: 0xfffafa, + springgreen: 0x00ff7f, + steelblue: 0x4682b4, + tan: 0xd2b48c, + teal: 0x008080, + thistle: 0xd8bfd8, + tomato: 0xff6347, + turquoise: 0x40e0d0, + violet: 0xee82ee, + wheat: 0xf5deb3, + white: 0xffffff, + whitesmoke: 0xf5f5f5, + yellow: 0xffff00, + yellowgreen: 0x9acd32 + }; + + define(Color, color, { + copy(channels) { + return Object.assign(new this.constructor, this, channels); + }, + displayable() { + return this.rgb().displayable(); + }, + hex: color_formatHex, // Deprecated! Use color.formatHex. + formatHex: color_formatHex, + formatHex8: color_formatHex8, + formatHsl: color_formatHsl, + formatRgb: color_formatRgb, + toString: color_formatRgb + }); + + function color_formatHex() { + return this.rgb().formatHex(); + } + + function color_formatHex8() { + return this.rgb().formatHex8(); + } + + function color_formatHsl() { + return hslConvert(this).formatHsl(); + } + + function color_formatRgb() { + return this.rgb().formatRgb(); + } + + function color(format) { + var m, l; + format = (format + "").trim().toLowerCase(); + return (m = reHex.exec(format)) ? (l = m[1].length, m = parseInt(m[1], 16), l === 6 ? rgbn(m) // #ff0000 + : l === 3 ? new Rgb((m >> 8 & 0xf) | (m >> 4 & 0xf0), (m >> 4 & 0xf) | (m & 0xf0), ((m & 0xf) << 4) | (m & 0xf), 1) // #f00 + : l === 8 ? rgba(m >> 24 & 0xff, m >> 16 & 0xff, m >> 8 & 0xff, (m & 0xff) / 0xff) // #ff000000 + : l === 4 ? rgba((m >> 12 & 0xf) | (m >> 8 & 0xf0), (m >> 8 & 0xf) | (m >> 4 & 0xf0), (m >> 4 & 0xf) | (m & 0xf0), (((m & 0xf) << 4) | (m & 0xf)) / 0xff) // #f000 + : null) // invalid hex + : (m = reRgbInteger.exec(format)) ? new Rgb(m[1], m[2], m[3], 1) // rgb(255, 0, 0) + : (m = reRgbPercent.exec(format)) ? new Rgb(m[1] * 255 / 100, m[2] * 255 / 100, m[3] * 255 / 100, 1) // rgb(100%, 0%, 0%) + : (m = reRgbaInteger.exec(format)) ? rgba(m[1], m[2], m[3], m[4]) // rgba(255, 0, 0, 1) + : (m = reRgbaPercent.exec(format)) ? rgba(m[1] * 255 / 100, m[2] * 255 / 100, m[3] * 255 / 100, m[4]) // rgb(100%, 0%, 0%, 1) + : (m = reHslPercent.exec(format)) ? hsla(m[1], m[2] / 100, m[3] / 100, 1) // hsl(120, 50%, 50%) + : (m = reHslaPercent.exec(format)) ? hsla(m[1], m[2] / 100, m[3] / 100, m[4]) // hsla(120, 50%, 50%, 1) + : named.hasOwnProperty(format) ? rgbn(named[format]) // eslint-disable-line no-prototype-builtins + : format === "transparent" ? new Rgb(NaN, NaN, NaN, 0) + : null; + } + + function rgbn(n) { + return new Rgb(n >> 16 & 0xff, n >> 8 & 0xff, n & 0xff, 1); + } + + function rgba(r, g, b, a) { + if (a <= 0) r = g = b = NaN; + return new Rgb(r, g, b, a); + } + + function rgbConvert(o) { + if (!(o instanceof Color)) o = color(o); + if (!o) return new Rgb; + o = o.rgb(); + return new Rgb(o.r, o.g, o.b, o.opacity); + } + + function rgb(r, g, b, opacity) { + return arguments.length === 1 ? rgbConvert(r) : new Rgb(r, g, b, opacity == null ? 1 : opacity); + } + + function Rgb(r, g, b, opacity) { + this.r = +r; + this.g = +g; + this.b = +b; + this.opacity = +opacity; + } + + define(Rgb, rgb, extend(Color, { + brighter(k) { + k = k == null ? brighter : Math.pow(brighter, k); + return new Rgb(this.r * k, this.g * k, this.b * k, this.opacity); + }, + darker(k) { + k = k == null ? darker : Math.pow(darker, k); + return new Rgb(this.r * k, this.g * k, this.b * k, this.opacity); + }, + rgb() { + return this; + }, + clamp() { + return new Rgb(clampi(this.r), clampi(this.g), clampi(this.b), clampa(this.opacity)); + }, + displayable() { + return (-0.5 <= this.r && this.r < 255.5) + && (-0.5 <= this.g && this.g < 255.5) + && (-0.5 <= this.b && this.b < 255.5) + && (0 <= this.opacity && this.opacity <= 1); + }, + hex: rgb_formatHex, // Deprecated! Use color.formatHex. + formatHex: rgb_formatHex, + formatHex8: rgb_formatHex8, + formatRgb: rgb_formatRgb, + toString: rgb_formatRgb + })); + + function rgb_formatHex() { + return `#${hex(this.r)}${hex(this.g)}${hex(this.b)}`; + } + + function rgb_formatHex8() { + return `#${hex(this.r)}${hex(this.g)}${hex(this.b)}${hex((isNaN(this.opacity) ? 1 : this.opacity) * 255)}`; + } + + function rgb_formatRgb() { + const a = clampa(this.opacity); + return `${a === 1 ? "rgb(" : "rgba("}${clampi(this.r)}, ${clampi(this.g)}, ${clampi(this.b)}${a === 1 ? ")" : `, ${a})`}`; + } + + function clampa(opacity) { + return isNaN(opacity) ? 1 : Math.max(0, Math.min(1, opacity)); + } + + function clampi(value) { + return Math.max(0, Math.min(255, Math.round(value) || 0)); + } + + function hex(value) { + value = clampi(value); + return (value < 16 ? "0" : "") + value.toString(16); + } + + function hsla(h, s, l, a) { + if (a <= 0) h = s = l = NaN; + else if (l <= 0 || l >= 1) h = s = NaN; + else if (s <= 0) h = NaN; + return new Hsl(h, s, l, a); + } + + function hslConvert(o) { + if (o instanceof Hsl) return new Hsl(o.h, o.s, o.l, o.opacity); + if (!(o instanceof Color)) o = color(o); + if (!o) return new Hsl; + if (o instanceof Hsl) return o; + o = o.rgb(); + var r = o.r / 255, + g = o.g / 255, + b = o.b / 255, + min = Math.min(r, g, b), + max = Math.max(r, g, b), + h = NaN, + s = max - min, + l = (max + min) / 2; + if (s) { + if (r === max) h = (g - b) / s + (g < b) * 6; + else if (g === max) h = (b - r) / s + 2; + else h = (r - g) / s + 4; + s /= l < 0.5 ? max + min : 2 - max - min; + h *= 60; + } else { + s = l > 0 && l < 1 ? 0 : h; + } + return new Hsl(h, s, l, o.opacity); + } + + function hsl(h, s, l, opacity) { + return arguments.length === 1 ? hslConvert(h) : new Hsl(h, s, l, opacity == null ? 1 : opacity); + } + + function Hsl(h, s, l, opacity) { + this.h = +h; + this.s = +s; + this.l = +l; + this.opacity = +opacity; + } + + define(Hsl, hsl, extend(Color, { + brighter(k) { + k = k == null ? brighter : Math.pow(brighter, k); + return new Hsl(this.h, this.s, this.l * k, this.opacity); + }, + darker(k) { + k = k == null ? darker : Math.pow(darker, k); + return new Hsl(this.h, this.s, this.l * k, this.opacity); + }, + rgb() { + var h = this.h % 360 + (this.h < 0) * 360, + s = isNaN(h) || isNaN(this.s) ? 0 : this.s, + l = this.l, + m2 = l + (l < 0.5 ? l : 1 - l) * s, + m1 = 2 * l - m2; + return new Rgb( + hsl2rgb(h >= 240 ? h - 240 : h + 120, m1, m2), + hsl2rgb(h, m1, m2), + hsl2rgb(h < 120 ? h + 240 : h - 120, m1, m2), + this.opacity + ); + }, + clamp() { + return new Hsl(clamph(this.h), clampt(this.s), clampt(this.l), clampa(this.opacity)); + }, + displayable() { + return (0 <= this.s && this.s <= 1 || isNaN(this.s)) + && (0 <= this.l && this.l <= 1) + && (0 <= this.opacity && this.opacity <= 1); + }, + formatHsl() { + const a = clampa(this.opacity); + return `${a === 1 ? "hsl(" : "hsla("}${clamph(this.h)}, ${clampt(this.s) * 100}%, ${clampt(this.l) * 100}%${a === 1 ? ")" : `, ${a})`}`; + } + })); + + function clamph(value) { + value = (value || 0) % 360; + return value < 0 ? value + 360 : value; + } + + function clampt(value) { + return Math.max(0, Math.min(1, value || 0)); + } + + /* From FvD 13.37, CSS Color Module Level 3 */ + function hsl2rgb(h, m1, m2) { + return (h < 60 ? m1 + (m2 - m1) * h / 60 + : h < 180 ? m2 + : h < 240 ? m1 + (m2 - m1) * (240 - h) / 60 + : m1) * 255; + } + + var constant$2 = x => () => x; + + function linear(a, d) { + return function(t) { + return a + t * d; + }; + } + + function exponential(a, b, y) { + return a = Math.pow(a, y), b = Math.pow(b, y) - a, y = 1 / y, function(t) { + return Math.pow(a + t * b, y); + }; + } + + function gamma(y) { + return (y = +y) === 1 ? nogamma : function(a, b) { + return b - a ? exponential(a, b, y) : constant$2(isNaN(a) ? b : a); + }; + } + + function nogamma(a, b) { + var d = b - a; + return d ? linear(a, d) : constant$2(isNaN(a) ? b : a); + } + + var interpolateRgb = (function rgbGamma(y) { + var color = gamma(y); + + function rgb$1(start, end) { + var r = color((start = rgb(start)).r, (end = rgb(end)).r), + g = color(start.g, end.g), + b = color(start.b, end.b), + opacity = nogamma(start.opacity, end.opacity); + return function(t) { + start.r = r(t); + start.g = g(t); + start.b = b(t); + start.opacity = opacity(t); + return start + ""; + }; + } + + rgb$1.gamma = rgbGamma; + + return rgb$1; + })(1); + + function interpolateNumber(a, b) { + return a = +a, b = +b, function(t) { + return a * (1 - t) + b * t; + }; + } + + var reA = /[-+]?(?:\d+\.?\d*|\.?\d+)(?:[eE][-+]?\d+)?/g, + reB = new RegExp(reA.source, "g"); + + function zero(b) { + return function() { + return b; + }; + } + + function one(b) { + return function(t) { + return b(t) + ""; + }; + } + + function interpolateString(a, b) { + var bi = reA.lastIndex = reB.lastIndex = 0, // scan index for next number in b + am, // current match in a + bm, // current match in b + bs, // string preceding current number in b, if any + i = -1, // index in s + s = [], // string constants and placeholders + q = []; // number interpolators + + // Coerce inputs to strings. + a = a + "", b = b + ""; + + // Interpolate pairs of numbers in a & b. + while ((am = reA.exec(a)) + && (bm = reB.exec(b))) { + if ((bs = bm.index) > bi) { // a string precedes the next number in b + bs = b.slice(bi, bs); + if (s[i]) s[i] += bs; // coalesce with previous string + else s[++i] = bs; + } + if ((am = am[0]) === (bm = bm[0])) { // numbers in a & b match + if (s[i]) s[i] += bm; // coalesce with previous string + else s[++i] = bm; + } else { // interpolate non-matching numbers + s[++i] = null; + q.push({i: i, x: interpolateNumber(am, bm)}); + } + bi = reB.lastIndex; + } + + // Add remains of b. + if (bi < b.length) { + bs = b.slice(bi); + if (s[i]) s[i] += bs; // coalesce with previous string + else s[++i] = bs; + } + + // Special optimization for only a single match. + // Otherwise, interpolate each of the numbers and rejoin the string. + return s.length < 2 ? (q[0] + ? one(q[0].x) + : zero(b)) + : (b = q.length, function(t) { + for (var i = 0, o; i < b; ++i) s[(o = q[i]).i] = o.x(t); + return s.join(""); + }); + } + + var degrees = 180 / Math.PI; + + var identity$1 = { + translateX: 0, + translateY: 0, + rotate: 0, + skewX: 0, + scaleX: 1, + scaleY: 1 + }; + + function decompose(a, b, c, d, e, f) { + var scaleX, scaleY, skewX; + if (scaleX = Math.sqrt(a * a + b * b)) a /= scaleX, b /= scaleX; + if (skewX = a * c + b * d) c -= a * skewX, d -= b * skewX; + if (scaleY = Math.sqrt(c * c + d * d)) c /= scaleY, d /= scaleY, skewX /= scaleY; + if (a * d < b * c) a = -a, b = -b, skewX = -skewX, scaleX = -scaleX; + return { + translateX: e, + translateY: f, + rotate: Math.atan2(b, a) * degrees, + skewX: Math.atan(skewX) * degrees, + scaleX: scaleX, + scaleY: scaleY + }; + } + + var svgNode; + + /* eslint-disable no-undef */ + function parseCss(value) { + const m = new (typeof DOMMatrix === "function" ? DOMMatrix : WebKitCSSMatrix)(value + ""); + return m.isIdentity ? identity$1 : decompose(m.a, m.b, m.c, m.d, m.e, m.f); + } + + function parseSvg(value) { + if (value == null) return identity$1; + if (!svgNode) svgNode = document.createElementNS("http://www.w3.org/2000/svg", "g"); + svgNode.setAttribute("transform", value); + if (!(value = svgNode.transform.baseVal.consolidate())) return identity$1; + value = value.matrix; + return decompose(value.a, value.b, value.c, value.d, value.e, value.f); + } + + function interpolateTransform(parse, pxComma, pxParen, degParen) { + + function pop(s) { + return s.length ? s.pop() + " " : ""; + } + + function translate(xa, ya, xb, yb, s, q) { + if (xa !== xb || ya !== yb) { + var i = s.push("translate(", null, pxComma, null, pxParen); + q.push({i: i - 4, x: interpolateNumber(xa, xb)}, {i: i - 2, x: interpolateNumber(ya, yb)}); + } else if (xb || yb) { + s.push("translate(" + xb + pxComma + yb + pxParen); + } + } + + function rotate(a, b, s, q) { + if (a !== b) { + if (a - b > 180) b += 360; else if (b - a > 180) a += 360; // shortest path + q.push({i: s.push(pop(s) + "rotate(", null, degParen) - 2, x: interpolateNumber(a, b)}); + } else if (b) { + s.push(pop(s) + "rotate(" + b + degParen); + } + } + + function skewX(a, b, s, q) { + if (a !== b) { + q.push({i: s.push(pop(s) + "skewX(", null, degParen) - 2, x: interpolateNumber(a, b)}); + } else if (b) { + s.push(pop(s) + "skewX(" + b + degParen); + } + } + + function scale(xa, ya, xb, yb, s, q) { + if (xa !== xb || ya !== yb) { + var i = s.push(pop(s) + "scale(", null, ",", null, ")"); + q.push({i: i - 4, x: interpolateNumber(xa, xb)}, {i: i - 2, x: interpolateNumber(ya, yb)}); + } else if (xb !== 1 || yb !== 1) { + s.push(pop(s) + "scale(" + xb + "," + yb + ")"); + } + } + + return function(a, b) { + var s = [], // string constants and placeholders + q = []; // number interpolators + a = parse(a), b = parse(b); + translate(a.translateX, a.translateY, b.translateX, b.translateY, s, q); + rotate(a.rotate, b.rotate, s, q); + skewX(a.skewX, b.skewX, s, q); + scale(a.scaleX, a.scaleY, b.scaleX, b.scaleY, s, q); + a = b = null; // gc + return function(t) { + var i = -1, n = q.length, o; + while (++i < n) s[(o = q[i]).i] = o.x(t); + return s.join(""); + }; + }; + } + + var interpolateTransformCss = interpolateTransform(parseCss, "px, ", "px)", "deg)"); + var interpolateTransformSvg = interpolateTransform(parseSvg, ", ", ")", ")"); + + var epsilon2 = 1e-12; + + function cosh(x) { + return ((x = Math.exp(x)) + 1 / x) / 2; + } + + function sinh(x) { + return ((x = Math.exp(x)) - 1 / x) / 2; + } + + function tanh(x) { + return ((x = Math.exp(2 * x)) - 1) / (x + 1); + } + + var interpolateZoom = (function zoomRho(rho, rho2, rho4) { + + // p0 = [ux0, uy0, w0] + // p1 = [ux1, uy1, w1] + function zoom(p0, p1) { + var ux0 = p0[0], uy0 = p0[1], w0 = p0[2], + ux1 = p1[0], uy1 = p1[1], w1 = p1[2], + dx = ux1 - ux0, + dy = uy1 - uy0, + d2 = dx * dx + dy * dy, + i, + S; + + // Special case for u0 ≅ u1. + if (d2 < epsilon2) { + S = Math.log(w1 / w0) / rho; + i = function(t) { + return [ + ux0 + t * dx, + uy0 + t * dy, + w0 * Math.exp(rho * t * S) + ]; + }; + } + + // General case. + else { + var d1 = Math.sqrt(d2), + b0 = (w1 * w1 - w0 * w0 + rho4 * d2) / (2 * w0 * rho2 * d1), + b1 = (w1 * w1 - w0 * w0 - rho4 * d2) / (2 * w1 * rho2 * d1), + r0 = Math.log(Math.sqrt(b0 * b0 + 1) - b0), + r1 = Math.log(Math.sqrt(b1 * b1 + 1) - b1); + S = (r1 - r0) / rho; + i = function(t) { + var s = t * S, + coshr0 = cosh(r0), + u = w0 / (rho2 * d1) * (coshr0 * tanh(rho * s + r0) - sinh(r0)); + return [ + ux0 + u * dx, + uy0 + u * dy, + w0 * coshr0 / cosh(rho * s + r0) + ]; + }; + } + + i.duration = S * 1000 * rho / Math.SQRT2; + + return i; + } + + zoom.rho = function(_) { + var _1 = Math.max(1e-3, +_), _2 = _1 * _1, _4 = _2 * _2; + return zoomRho(_1, _2, _4); + }; + + return zoom; + })(Math.SQRT2, 2, 4); + + var frame = 0, // is an animation frame pending? + timeout$1 = 0, // is a timeout pending? + interval = 0, // are any timers active? + pokeDelay = 1000, // how frequently we check for clock skew + taskHead, + taskTail, + clockLast = 0, + clockNow = 0, + clockSkew = 0, + clock = typeof performance === "object" && performance.now ? performance : Date, + setFrame = typeof window === "object" && window.requestAnimationFrame ? window.requestAnimationFrame.bind(window) : function(f) { setTimeout(f, 17); }; + + function now$3() { + return clockNow || (setFrame(clearNow), clockNow = clock.now() + clockSkew); + } + + function clearNow() { + clockNow = 0; + } + + function Timer() { + this._call = + this._time = + this._next = null; + } + + Timer.prototype = timer.prototype = { + constructor: Timer, + restart: function(callback, delay, time) { + if (typeof callback !== "function") throw new TypeError("callback is not a function"); + time = (time == null ? now$3() : +time) + (delay == null ? 0 : +delay); + if (!this._next && taskTail !== this) { + if (taskTail) taskTail._next = this; + else taskHead = this; + taskTail = this; + } + this._call = callback; + this._time = time; + sleep(); + }, + stop: function() { + if (this._call) { + this._call = null; + this._time = Infinity; + sleep(); + } + } + }; + + function timer(callback, delay, time) { + var t = new Timer; + t.restart(callback, delay, time); + return t; + } + + function timerFlush() { + now$3(); // Get the current time, if not already set. + ++frame; // Pretend we’ve set an alarm, if we haven’t already. + var t = taskHead, e; + while (t) { + if ((e = clockNow - t._time) >= 0) t._call.call(undefined, e); + t = t._next; + } + --frame; + } + + function wake() { + clockNow = (clockLast = clock.now()) + clockSkew; + frame = timeout$1 = 0; + try { + timerFlush(); + } finally { + frame = 0; + nap(); + clockNow = 0; + } + } + + function poke() { + var now = clock.now(), delay = now - clockLast; + if (delay > pokeDelay) clockSkew -= delay, clockLast = now; + } + + function nap() { + var t0, t1 = taskHead, t2, time = Infinity; + while (t1) { + if (t1._call) { + if (time > t1._time) time = t1._time; + t0 = t1, t1 = t1._next; + } else { + t2 = t1._next, t1._next = null; + t1 = t0 ? t0._next = t2 : taskHead = t2; + } + } + taskTail = t0; + sleep(time); + } + + function sleep(time) { + if (frame) return; // Soonest alarm already set, or will be. + if (timeout$1) timeout$1 = clearTimeout(timeout$1); + var delay = time - clockNow; // Strictly less than if we recomputed clockNow. + if (delay > 24) { + if (time < Infinity) timeout$1 = setTimeout(wake, time - clock.now() - clockSkew); + if (interval) interval = clearInterval(interval); + } else { + if (!interval) clockLast = clock.now(), interval = setInterval(poke, pokeDelay); + frame = 1, setFrame(wake); + } + } + + function timeout(callback, delay, time) { + var t = new Timer; + delay = delay == null ? 0 : +delay; + t.restart(elapsed => { + t.stop(); + callback(elapsed + delay); + }, delay, time); + return t; + } + + var emptyOn = dispatch("start", "end", "cancel", "interrupt"); + var emptyTween = []; + + var CREATED = 0; + var SCHEDULED = 1; + var STARTING = 2; + var STARTED = 3; + var RUNNING = 4; + var ENDING = 5; + var ENDED = 6; + + function schedule(node, name, id, index, group, timing) { + var schedules = node.__transition; + if (!schedules) node.__transition = {}; + else if (id in schedules) return; + create(node, id, { + name: name, + index: index, // For context during callback. + group: group, // For context during callback. + on: emptyOn, + tween: emptyTween, + time: timing.time, + delay: timing.delay, + duration: timing.duration, + ease: timing.ease, + timer: null, + state: CREATED + }); + } + + function init(node, id) { + var schedule = get(node, id); + if (schedule.state > CREATED) throw new Error("too late; already scheduled"); + return schedule; + } + + function set(node, id) { + var schedule = get(node, id); + if (schedule.state > STARTED) throw new Error("too late; already running"); + return schedule; + } + + function get(node, id) { + var schedule = node.__transition; + if (!schedule || !(schedule = schedule[id])) throw new Error("transition not found"); + return schedule; + } + + function create(node, id, self) { + var schedules = node.__transition, + tween; + + // Initialize the self timer when the transition is created. + // Note the actual delay is not known until the first callback! + schedules[id] = self; + self.timer = timer(schedule, 0, self.time); + + function schedule(elapsed) { + self.state = SCHEDULED; + self.timer.restart(start, self.delay, self.time); + + // If the elapsed delay is less than our first sleep, start immediately. + if (self.delay <= elapsed) start(elapsed - self.delay); + } + + function start(elapsed) { + var i, j, n, o; + + // If the state is not SCHEDULED, then we previously errored on start. + if (self.state !== SCHEDULED) return stop(); + + for (i in schedules) { + o = schedules[i]; + if (o.name !== self.name) continue; + + // While this element already has a starting transition during this frame, + // defer starting an interrupting transition until that transition has a + // chance to tick (and possibly end); see d3/d3-transition#54! + if (o.state === STARTED) return timeout(start); + + // Interrupt the active transition, if any. + if (o.state === RUNNING) { + o.state = ENDED; + o.timer.stop(); + o.on.call("interrupt", node, node.__data__, o.index, o.group); + delete schedules[i]; + } + + // Cancel any pre-empted transitions. + else if (+i < id) { + o.state = ENDED; + o.timer.stop(); + o.on.call("cancel", node, node.__data__, o.index, o.group); + delete schedules[i]; + } + } + + // Defer the first tick to end of the current frame; see d3/d3#1576. + // Note the transition may be canceled after start and before the first tick! + // Note this must be scheduled before the start event; see d3/d3-transition#16! + // Assuming this is successful, subsequent callbacks go straight to tick. + timeout(function() { + if (self.state === STARTED) { + self.state = RUNNING; + self.timer.restart(tick, self.delay, self.time); + tick(elapsed); + } + }); + + // Dispatch the start event. + // Note this must be done before the tween are initialized. + self.state = STARTING; + self.on.call("start", node, node.__data__, self.index, self.group); + if (self.state !== STARTING) return; // interrupted + self.state = STARTED; + + // Initialize the tween, deleting null tween. + tween = new Array(n = self.tween.length); + for (i = 0, j = -1; i < n; ++i) { + if (o = self.tween[i].value.call(node, node.__data__, self.index, self.group)) { + tween[++j] = o; + } + } + tween.length = j + 1; + } + + function tick(elapsed) { + var t = elapsed < self.duration ? self.ease.call(null, elapsed / self.duration) : (self.timer.restart(stop), self.state = ENDING, 1), + i = -1, + n = tween.length; + + while (++i < n) { + tween[i].call(node, t); + } + + // Dispatch the end event. + if (self.state === ENDING) { + self.on.call("end", node, node.__data__, self.index, self.group); + stop(); + } + } + + function stop() { + self.state = ENDED; + self.timer.stop(); + delete schedules[id]; + for (var i in schedules) return; // eslint-disable-line no-unused-vars + delete node.__transition; + } + } + + function interrupt(node, name) { + var schedules = node.__transition, + schedule, + active, + empty = true, + i; + + if (!schedules) return; + + name = name == null ? null : name + ""; + + for (i in schedules) { + if ((schedule = schedules[i]).name !== name) { empty = false; continue; } + active = schedule.state > STARTING && schedule.state < ENDING; + schedule.state = ENDED; + schedule.timer.stop(); + schedule.on.call(active ? "interrupt" : "cancel", node, node.__data__, schedule.index, schedule.group); + delete schedules[i]; + } + + if (empty) delete node.__transition; + } + + function selection_interrupt(name) { + return this.each(function() { + interrupt(this, name); + }); + } + + function tweenRemove(id, name) { + var tween0, tween1; + return function() { + var schedule = set(this, id), + tween = schedule.tween; + + // If this node shared tween with the previous node, + // just assign the updated shared tween and we’re done! + // Otherwise, copy-on-write. + if (tween !== tween0) { + tween1 = tween0 = tween; + for (var i = 0, n = tween1.length; i < n; ++i) { + if (tween1[i].name === name) { + tween1 = tween1.slice(); + tween1.splice(i, 1); + break; + } + } + } + + schedule.tween = tween1; + }; + } + + function tweenFunction(id, name, value) { + var tween0, tween1; + if (typeof value !== "function") throw new Error; + return function() { + var schedule = set(this, id), + tween = schedule.tween; + + // If this node shared tween with the previous node, + // just assign the updated shared tween and we’re done! + // Otherwise, copy-on-write. + if (tween !== tween0) { + tween1 = (tween0 = tween).slice(); + for (var t = {name: name, value: value}, i = 0, n = tween1.length; i < n; ++i) { + if (tween1[i].name === name) { + tween1[i] = t; + break; + } + } + if (i === n) tween1.push(t); + } + + schedule.tween = tween1; + }; + } + + function transition_tween(name, value) { + var id = this._id; + + name += ""; + + if (arguments.length < 2) { + var tween = get(this.node(), id).tween; + for (var i = 0, n = tween.length, t; i < n; ++i) { + if ((t = tween[i]).name === name) { + return t.value; + } + } + return null; + } + + return this.each((value == null ? tweenRemove : tweenFunction)(id, name, value)); + } + + function tweenValue(transition, name, value) { + var id = transition._id; + + transition.each(function() { + var schedule = set(this, id); + (schedule.value || (schedule.value = {}))[name] = value.apply(this, arguments); + }); + + return function(node) { + return get(node, id).value[name]; + }; + } + + function interpolate(a, b) { + var c; + return (typeof b === "number" ? interpolateNumber + : b instanceof color ? interpolateRgb + : (c = color(b)) ? (b = c, interpolateRgb) + : interpolateString)(a, b); + } + + function attrRemove(name) { + return function() { + this.removeAttribute(name); + }; + } + + function attrRemoveNS(fullname) { + return function() { + this.removeAttributeNS(fullname.space, fullname.local); + }; + } + + function attrConstant(name, interpolate, value1) { + var string00, + string1 = value1 + "", + interpolate0; + return function() { + var string0 = this.getAttribute(name); + return string0 === string1 ? null + : string0 === string00 ? interpolate0 + : interpolate0 = interpolate(string00 = string0, value1); + }; + } + + function attrConstantNS(fullname, interpolate, value1) { + var string00, + string1 = value1 + "", + interpolate0; + return function() { + var string0 = this.getAttributeNS(fullname.space, fullname.local); + return string0 === string1 ? null + : string0 === string00 ? interpolate0 + : interpolate0 = interpolate(string00 = string0, value1); + }; + } + + function attrFunction(name, interpolate, value) { + var string00, + string10, + interpolate0; + return function() { + var string0, value1 = value(this), string1; + if (value1 == null) return void this.removeAttribute(name); + string0 = this.getAttribute(name); + string1 = value1 + ""; + return string0 === string1 ? null + : string0 === string00 && string1 === string10 ? interpolate0 + : (string10 = string1, interpolate0 = interpolate(string00 = string0, value1)); + }; + } + + function attrFunctionNS(fullname, interpolate, value) { + var string00, + string10, + interpolate0; + return function() { + var string0, value1 = value(this), string1; + if (value1 == null) return void this.removeAttributeNS(fullname.space, fullname.local); + string0 = this.getAttributeNS(fullname.space, fullname.local); + string1 = value1 + ""; + return string0 === string1 ? null + : string0 === string00 && string1 === string10 ? interpolate0 + : (string10 = string1, interpolate0 = interpolate(string00 = string0, value1)); + }; + } + + function transition_attr(name, value) { + var fullname = namespace(name), i = fullname === "transform" ? interpolateTransformSvg : interpolate; + return this.attrTween(name, typeof value === "function" + ? (fullname.local ? attrFunctionNS : attrFunction)(fullname, i, tweenValue(this, "attr." + name, value)) + : value == null ? (fullname.local ? attrRemoveNS : attrRemove)(fullname) + : (fullname.local ? attrConstantNS : attrConstant)(fullname, i, value)); + } + + function attrInterpolate(name, i) { + return function(t) { + this.setAttribute(name, i.call(this, t)); + }; + } + + function attrInterpolateNS(fullname, i) { + return function(t) { + this.setAttributeNS(fullname.space, fullname.local, i.call(this, t)); + }; + } + + function attrTweenNS(fullname, value) { + var t0, i0; + function tween() { + var i = value.apply(this, arguments); + if (i !== i0) t0 = (i0 = i) && attrInterpolateNS(fullname, i); + return t0; + } + tween._value = value; + return tween; + } + + function attrTween(name, value) { + var t0, i0; + function tween() { + var i = value.apply(this, arguments); + if (i !== i0) t0 = (i0 = i) && attrInterpolate(name, i); + return t0; + } + tween._value = value; + return tween; + } + + function transition_attrTween(name, value) { + var key = "attr." + name; + if (arguments.length < 2) return (key = this.tween(key)) && key._value; + if (value == null) return this.tween(key, null); + if (typeof value !== "function") throw new Error; + var fullname = namespace(name); + return this.tween(key, (fullname.local ? attrTweenNS : attrTween)(fullname, value)); + } + + function delayFunction(id, value) { + return function() { + init(this, id).delay = +value.apply(this, arguments); + }; + } + + function delayConstant(id, value) { + return value = +value, function() { + init(this, id).delay = value; + }; + } + + function transition_delay(value) { + var id = this._id; + + return arguments.length + ? this.each((typeof value === "function" + ? delayFunction + : delayConstant)(id, value)) + : get(this.node(), id).delay; + } + + function durationFunction(id, value) { + return function() { + set(this, id).duration = +value.apply(this, arguments); + }; + } + + function durationConstant(id, value) { + return value = +value, function() { + set(this, id).duration = value; + }; + } + + function transition_duration(value) { + var id = this._id; + + return arguments.length + ? this.each((typeof value === "function" + ? durationFunction + : durationConstant)(id, value)) + : get(this.node(), id).duration; + } + + function easeConstant(id, value) { + if (typeof value !== "function") throw new Error; + return function() { + set(this, id).ease = value; + }; + } + + function transition_ease(value) { + var id = this._id; + + return arguments.length + ? this.each(easeConstant(id, value)) + : get(this.node(), id).ease; + } + + function easeVarying(id, value) { + return function() { + var v = value.apply(this, arguments); + if (typeof v !== "function") throw new Error; + set(this, id).ease = v; + }; + } + + function transition_easeVarying(value) { + if (typeof value !== "function") throw new Error; + return this.each(easeVarying(this._id, value)); + } + + function transition_filter(match) { + if (typeof match !== "function") match = matcher(match); + + for (var groups = this._groups, m = groups.length, subgroups = new Array(m), j = 0; j < m; ++j) { + for (var group = groups[j], n = group.length, subgroup = subgroups[j] = [], node, i = 0; i < n; ++i) { + if ((node = group[i]) && match.call(node, node.__data__, i, group)) { + subgroup.push(node); + } + } + } + + return new Transition(subgroups, this._parents, this._name, this._id); + } + + function transition_merge(transition) { + if (transition._id !== this._id) throw new Error; + + for (var groups0 = this._groups, groups1 = transition._groups, m0 = groups0.length, m1 = groups1.length, m = Math.min(m0, m1), merges = new Array(m0), j = 0; j < m; ++j) { + for (var group0 = groups0[j], group1 = groups1[j], n = group0.length, merge = merges[j] = new Array(n), node, i = 0; i < n; ++i) { + if (node = group0[i] || group1[i]) { + merge[i] = node; + } + } + } + + for (; j < m0; ++j) { + merges[j] = groups0[j]; + } + + return new Transition(merges, this._parents, this._name, this._id); + } + + function start(name) { + return (name + "").trim().split(/^|\s+/).every(function(t) { + var i = t.indexOf("."); + if (i >= 0) t = t.slice(0, i); + return !t || t === "start"; + }); + } + + function onFunction(id, name, listener) { + var on0, on1, sit = start(name) ? init : set; + return function() { + var schedule = sit(this, id), + on = schedule.on; + + // If this node shared a dispatch with the previous node, + // just assign the updated shared dispatch and we’re done! + // Otherwise, copy-on-write. + if (on !== on0) (on1 = (on0 = on).copy()).on(name, listener); + + schedule.on = on1; + }; + } + + function transition_on(name, listener) { + var id = this._id; + + return arguments.length < 2 + ? get(this.node(), id).on.on(name) + : this.each(onFunction(id, name, listener)); + } + + function removeFunction(id) { + return function() { + var parent = this.parentNode; + for (var i in this.__transition) if (+i !== id) return; + if (parent) parent.removeChild(this); + }; + } + + function transition_remove() { + return this.on("end.remove", removeFunction(this._id)); + } + + function transition_select(select) { + var name = this._name, + id = this._id; + + if (typeof select !== "function") select = selector(select); + + for (var groups = this._groups, m = groups.length, subgroups = new Array(m), j = 0; j < m; ++j) { + for (var group = groups[j], n = group.length, subgroup = subgroups[j] = new Array(n), node, subnode, i = 0; i < n; ++i) { + if ((node = group[i]) && (subnode = select.call(node, node.__data__, i, group))) { + if ("__data__" in node) subnode.__data__ = node.__data__; + subgroup[i] = subnode; + schedule(subgroup[i], name, id, i, subgroup, get(node, id)); + } + } + } + + return new Transition(subgroups, this._parents, name, id); + } + + function transition_selectAll(select) { + var name = this._name, + id = this._id; + + if (typeof select !== "function") select = selectorAll(select); + + for (var groups = this._groups, m = groups.length, subgroups = [], parents = [], j = 0; j < m; ++j) { + for (var group = groups[j], n = group.length, node, i = 0; i < n; ++i) { + if (node = group[i]) { + for (var children = select.call(node, node.__data__, i, group), child, inherit = get(node, id), k = 0, l = children.length; k < l; ++k) { + if (child = children[k]) { + schedule(child, name, id, k, children, inherit); + } + } + subgroups.push(children); + parents.push(node); + } + } + } + + return new Transition(subgroups, parents, name, id); + } + + var Selection = selection.prototype.constructor; + + function transition_selection() { + return new Selection(this._groups, this._parents); + } + + function styleNull(name, interpolate) { + var string00, + string10, + interpolate0; + return function() { + var string0 = styleValue(this, name), + string1 = (this.style.removeProperty(name), styleValue(this, name)); + return string0 === string1 ? null + : string0 === string00 && string1 === string10 ? interpolate0 + : interpolate0 = interpolate(string00 = string0, string10 = string1); + }; + } + + function styleRemove(name) { + return function() { + this.style.removeProperty(name); + }; + } + + function styleConstant(name, interpolate, value1) { + var string00, + string1 = value1 + "", + interpolate0; + return function() { + var string0 = styleValue(this, name); + return string0 === string1 ? null + : string0 === string00 ? interpolate0 + : interpolate0 = interpolate(string00 = string0, value1); + }; + } + + function styleFunction(name, interpolate, value) { + var string00, + string10, + interpolate0; + return function() { + var string0 = styleValue(this, name), + value1 = value(this), + string1 = value1 + ""; + if (value1 == null) string1 = value1 = (this.style.removeProperty(name), styleValue(this, name)); + return string0 === string1 ? null + : string0 === string00 && string1 === string10 ? interpolate0 + : (string10 = string1, interpolate0 = interpolate(string00 = string0, value1)); + }; + } + + function styleMaybeRemove(id, name) { + var on0, on1, listener0, key = "style." + name, event = "end." + key, remove; + return function() { + var schedule = set(this, id), + on = schedule.on, + listener = schedule.value[key] == null ? remove || (remove = styleRemove(name)) : undefined; + + // If this node shared a dispatch with the previous node, + // just assign the updated shared dispatch and we’re done! + // Otherwise, copy-on-write. + if (on !== on0 || listener0 !== listener) (on1 = (on0 = on).copy()).on(event, listener0 = listener); + + schedule.on = on1; + }; + } + + function transition_style(name, value, priority) { + var i = (name += "") === "transform" ? interpolateTransformCss : interpolate; + return value == null ? this + .styleTween(name, styleNull(name, i)) + .on("end.style." + name, styleRemove(name)) + : typeof value === "function" ? this + .styleTween(name, styleFunction(name, i, tweenValue(this, "style." + name, value))) + .each(styleMaybeRemove(this._id, name)) + : this + .styleTween(name, styleConstant(name, i, value), priority) + .on("end.style." + name, null); + } + + function styleInterpolate(name, i, priority) { + return function(t) { + this.style.setProperty(name, i.call(this, t), priority); + }; + } + + function styleTween(name, value, priority) { + var t, i0; + function tween() { + var i = value.apply(this, arguments); + if (i !== i0) t = (i0 = i) && styleInterpolate(name, i, priority); + return t; + } + tween._value = value; + return tween; + } + + function transition_styleTween(name, value, priority) { + var key = "style." + (name += ""); + if (arguments.length < 2) return (key = this.tween(key)) && key._value; + if (value == null) return this.tween(key, null); + if (typeof value !== "function") throw new Error; + return this.tween(key, styleTween(name, value, priority == null ? "" : priority)); + } + + function textConstant(value) { + return function() { + this.textContent = value; + }; + } + + function textFunction(value) { + return function() { + var value1 = value(this); + this.textContent = value1 == null ? "" : value1; + }; + } + + function transition_text(value) { + return this.tween("text", typeof value === "function" + ? textFunction(tweenValue(this, "text", value)) + : textConstant(value == null ? "" : value + "")); + } + + function textInterpolate(i) { + return function(t) { + this.textContent = i.call(this, t); + }; + } + + function textTween(value) { + var t0, i0; + function tween() { + var i = value.apply(this, arguments); + if (i !== i0) t0 = (i0 = i) && textInterpolate(i); + return t0; + } + tween._value = value; + return tween; + } + + function transition_textTween(value) { + var key = "text"; + if (arguments.length < 1) return (key = this.tween(key)) && key._value; + if (value == null) return this.tween(key, null); + if (typeof value !== "function") throw new Error; + return this.tween(key, textTween(value)); + } + + function transition_transition() { + var name = this._name, + id0 = this._id, + id1 = newId(); + + for (var groups = this._groups, m = groups.length, j = 0; j < m; ++j) { + for (var group = groups[j], n = group.length, node, i = 0; i < n; ++i) { + if (node = group[i]) { + var inherit = get(node, id0); + schedule(node, name, id1, i, group, { + time: inherit.time + inherit.delay + inherit.duration, + delay: 0, + duration: inherit.duration, + ease: inherit.ease + }); + } + } + } + + return new Transition(groups, this._parents, name, id1); + } + + function transition_end() { + var on0, on1, that = this, id = that._id, size = that.size(); + return new Promise(function(resolve, reject) { + var cancel = {value: reject}, + end = {value: function() { if (--size === 0) resolve(); }}; + + that.each(function() { + var schedule = set(this, id), + on = schedule.on; + + // If this node shared a dispatch with the previous node, + // just assign the updated shared dispatch and we’re done! + // Otherwise, copy-on-write. + if (on !== on0) { + on1 = (on0 = on).copy(); + on1._.cancel.push(cancel); + on1._.interrupt.push(cancel); + on1._.end.push(end); + } + + schedule.on = on1; + }); + + // The selection was empty, resolve end immediately + if (size === 0) resolve(); + }); + } + + var id = 0; + + function Transition(groups, parents, name, id) { + this._groups = groups; + this._parents = parents; + this._name = name; + this._id = id; + } + + function newId() { + return ++id; + } + + var selection_prototype = selection.prototype; + + Transition.prototype = { + constructor: Transition, + select: transition_select, + selectAll: transition_selectAll, + selectChild: selection_prototype.selectChild, + selectChildren: selection_prototype.selectChildren, + filter: transition_filter, + merge: transition_merge, + selection: transition_selection, + transition: transition_transition, + call: selection_prototype.call, + nodes: selection_prototype.nodes, + node: selection_prototype.node, + size: selection_prototype.size, + empty: selection_prototype.empty, + each: selection_prototype.each, + on: transition_on, + attr: transition_attr, + attrTween: transition_attrTween, + style: transition_style, + styleTween: transition_styleTween, + text: transition_text, + textTween: transition_textTween, + remove: transition_remove, + tween: transition_tween, + delay: transition_delay, + duration: transition_duration, + ease: transition_ease, + easeVarying: transition_easeVarying, + end: transition_end, + [Symbol.iterator]: selection_prototype[Symbol.iterator] + }; + + function cubicInOut(t) { + return ((t *= 2) <= 1 ? t * t * t : (t -= 2) * t * t + 2) / 2; + } + + var defaultTiming = { + time: null, // Set on use. + delay: 0, + duration: 250, + ease: cubicInOut + }; + + function inherit(node, id) { + var timing; + while (!(timing = node.__transition) || !(timing = timing[id])) { + if (!(node = node.parentNode)) { + throw new Error(`transition ${id} not found`); + } + } + return timing; + } + + function selection_transition(name) { + var id, + timing; + + if (name instanceof Transition) { + id = name._id, name = name._name; + } else { + id = newId(), (timing = defaultTiming).time = now$3(), name = name == null ? null : name + ""; + } + + for (var groups = this._groups, m = groups.length, j = 0; j < m; ++j) { + for (var group = groups[j], n = group.length, node, i = 0; i < n; ++i) { + if (node = group[i]) { + schedule(node, name, id, i, group, timing || inherit(node, id)); + } + } + } + + return new Transition(groups, this._parents, name, id); + } + + selection.prototype.interrupt = selection_interrupt; + selection.prototype.transition = selection_transition; + + var constant$1 = x => () => x; + + function ZoomEvent(type, { + sourceEvent, + target, + transform, + dispatch + }) { + Object.defineProperties(this, { + type: {value: type, enumerable: true, configurable: true}, + sourceEvent: {value: sourceEvent, enumerable: true, configurable: true}, + target: {value: target, enumerable: true, configurable: true}, + transform: {value: transform, enumerable: true, configurable: true}, + _: {value: dispatch} + }); + } + + function Transform(k, x, y) { + this.k = k; + this.x = x; + this.y = y; + } + + Transform.prototype = { + constructor: Transform, + scale: function(k) { + return k === 1 ? this : new Transform(this.k * k, this.x, this.y); + }, + translate: function(x, y) { + return x === 0 & y === 0 ? this : new Transform(this.k, this.x + this.k * x, this.y + this.k * y); + }, + apply: function(point) { + return [point[0] * this.k + this.x, point[1] * this.k + this.y]; + }, + applyX: function(x) { + return x * this.k + this.x; + }, + applyY: function(y) { + return y * this.k + this.y; + }, + invert: function(location) { + return [(location[0] - this.x) / this.k, (location[1] - this.y) / this.k]; + }, + invertX: function(x) { + return (x - this.x) / this.k; + }, + invertY: function(y) { + return (y - this.y) / this.k; + }, + rescaleX: function(x) { + return x.copy().domain(x.range().map(this.invertX, this).map(x.invert, x)); + }, + rescaleY: function(y) { + return y.copy().domain(y.range().map(this.invertY, this).map(y.invert, y)); + }, + toString: function() { + return "translate(" + this.x + "," + this.y + ") scale(" + this.k + ")"; + } + }; + + var identity = new Transform(1, 0, 0); + + transform.prototype = Transform.prototype; + + function transform(node) { + while (!node.__zoom) if (!(node = node.parentNode)) return identity; + return node.__zoom; + } + + function nopropagation(event) { + event.stopImmediatePropagation(); + } + + function noevent(event) { + event.preventDefault(); + event.stopImmediatePropagation(); + } + + // Ignore right-click, since that should open the context menu. + // except for pinch-to-zoom, which is sent as a wheel+ctrlKey event + function defaultFilter(event) { + return (!event.ctrlKey || event.type === 'wheel') && !event.button; + } + + function defaultExtent() { + var e = this; + if (e instanceof SVGElement) { + e = e.ownerSVGElement || e; + if (e.hasAttribute("viewBox")) { + e = e.viewBox.baseVal; + return [[e.x, e.y], [e.x + e.width, e.y + e.height]]; + } + return [[0, 0], [e.width.baseVal.value, e.height.baseVal.value]]; + } + return [[0, 0], [e.clientWidth, e.clientHeight]]; + } + + function defaultTransform() { + return this.__zoom || identity; + } + + function defaultWheelDelta(event) { + return -event.deltaY * (event.deltaMode === 1 ? 0.05 : event.deltaMode ? 1 : 0.002) * (event.ctrlKey ? 10 : 1); + } + + function defaultTouchable() { + return navigator.maxTouchPoints || ("ontouchstart" in this); + } + + function defaultConstrain(transform, extent, translateExtent) { + var dx0 = transform.invertX(extent[0][0]) - translateExtent[0][0], + dx1 = transform.invertX(extent[1][0]) - translateExtent[1][0], + dy0 = transform.invertY(extent[0][1]) - translateExtent[0][1], + dy1 = transform.invertY(extent[1][1]) - translateExtent[1][1]; + return transform.translate( + dx1 > dx0 ? (dx0 + dx1) / 2 : Math.min(0, dx0) || Math.max(0, dx1), + dy1 > dy0 ? (dy0 + dy1) / 2 : Math.min(0, dy0) || Math.max(0, dy1) + ); + } + + function d3Zoom() { + var filter = defaultFilter, + extent = defaultExtent, + constrain = defaultConstrain, + wheelDelta = defaultWheelDelta, + touchable = defaultTouchable, + scaleExtent = [0, Infinity], + translateExtent = [[-Infinity, -Infinity], [Infinity, Infinity]], + duration = 250, + interpolate = interpolateZoom, + listeners = dispatch("start", "zoom", "end"), + touchstarting, + touchfirst, + touchending, + touchDelay = 500, + wheelDelay = 150, + clickDistance2 = 0, + tapDistance = 10; + + function zoom(selection) { + selection + .property("__zoom", defaultTransform) + .on("wheel.zoom", wheeled, {passive: false}) + .on("mousedown.zoom", mousedowned) + .on("dblclick.zoom", dblclicked) + .filter(touchable) + .on("touchstart.zoom", touchstarted) + .on("touchmove.zoom", touchmoved) + .on("touchend.zoom touchcancel.zoom", touchended) + .style("-webkit-tap-highlight-color", "rgba(0,0,0,0)"); + } + + zoom.transform = function(collection, transform, point, event) { + var selection = collection.selection ? collection.selection() : collection; + selection.property("__zoom", defaultTransform); + if (collection !== selection) { + schedule(collection, transform, point, event); + } else { + selection.interrupt().each(function() { + gesture(this, arguments) + .event(event) + .start() + .zoom(null, typeof transform === "function" ? transform.apply(this, arguments) : transform) + .end(); + }); + } + }; + + zoom.scaleBy = function(selection, k, p, event) { + zoom.scaleTo(selection, function() { + var k0 = this.__zoom.k, + k1 = typeof k === "function" ? k.apply(this, arguments) : k; + return k0 * k1; + }, p, event); + }; + + zoom.scaleTo = function(selection, k, p, event) { + zoom.transform(selection, function() { + var e = extent.apply(this, arguments), + t0 = this.__zoom, + p0 = p == null ? centroid(e) : typeof p === "function" ? p.apply(this, arguments) : p, + p1 = t0.invert(p0), + k1 = typeof k === "function" ? k.apply(this, arguments) : k; + return constrain(translate(scale(t0, k1), p0, p1), e, translateExtent); + }, p, event); + }; + + zoom.translateBy = function(selection, x, y, event) { + zoom.transform(selection, function() { + return constrain(this.__zoom.translate( + typeof x === "function" ? x.apply(this, arguments) : x, + typeof y === "function" ? y.apply(this, arguments) : y + ), extent.apply(this, arguments), translateExtent); + }, null, event); + }; + + zoom.translateTo = function(selection, x, y, p, event) { + zoom.transform(selection, function() { + var e = extent.apply(this, arguments), + t = this.__zoom, + p0 = p == null ? centroid(e) : typeof p === "function" ? p.apply(this, arguments) : p; + return constrain(identity.translate(p0[0], p0[1]).scale(t.k).translate( + typeof x === "function" ? -x.apply(this, arguments) : -x, + typeof y === "function" ? -y.apply(this, arguments) : -y + ), e, translateExtent); + }, p, event); + }; + + function scale(transform, k) { + k = Math.max(scaleExtent[0], Math.min(scaleExtent[1], k)); + return k === transform.k ? transform : new Transform(k, transform.x, transform.y); + } + + function translate(transform, p0, p1) { + var x = p0[0] - p1[0] * transform.k, y = p0[1] - p1[1] * transform.k; + return x === transform.x && y === transform.y ? transform : new Transform(transform.k, x, y); + } + + function centroid(extent) { + return [(+extent[0][0] + +extent[1][0]) / 2, (+extent[0][1] + +extent[1][1]) / 2]; + } + + function schedule(transition, transform, point, event) { + transition + .on("start.zoom", function() { gesture(this, arguments).event(event).start(); }) + .on("interrupt.zoom end.zoom", function() { gesture(this, arguments).event(event).end(); }) + .tween("zoom", function() { + var that = this, + args = arguments, + g = gesture(that, args).event(event), + e = extent.apply(that, args), + p = point == null ? centroid(e) : typeof point === "function" ? point.apply(that, args) : point, + w = Math.max(e[1][0] - e[0][0], e[1][1] - e[0][1]), + a = that.__zoom, + b = typeof transform === "function" ? transform.apply(that, args) : transform, + i = interpolate(a.invert(p).concat(w / a.k), b.invert(p).concat(w / b.k)); + return function(t) { + if (t === 1) t = b; // Avoid rounding error on end. + else { var l = i(t), k = w / l[2]; t = new Transform(k, p[0] - l[0] * k, p[1] - l[1] * k); } + g.zoom(null, t); + }; + }); + } + + function gesture(that, args, clean) { + return (!clean && that.__zooming) || new Gesture(that, args); + } + + function Gesture(that, args) { + this.that = that; + this.args = args; + this.active = 0; + this.sourceEvent = null; + this.extent = extent.apply(that, args); + this.taps = 0; + } + + Gesture.prototype = { + event: function(event) { + if (event) this.sourceEvent = event; + return this; + }, + start: function() { + if (++this.active === 1) { + this.that.__zooming = this; + this.emit("start"); + } + return this; + }, + zoom: function(key, transform) { + if (this.mouse && key !== "mouse") this.mouse[1] = transform.invert(this.mouse[0]); + if (this.touch0 && key !== "touch") this.touch0[1] = transform.invert(this.touch0[0]); + if (this.touch1 && key !== "touch") this.touch1[1] = transform.invert(this.touch1[0]); + this.that.__zoom = transform; + this.emit("zoom"); + return this; + }, + end: function() { + if (--this.active === 0) { + delete this.that.__zooming; + this.emit("end"); + } + return this; + }, + emit: function(type) { + var d = d3Select(this.that).datum(); + listeners.call( + type, + this.that, + new ZoomEvent(type, { + sourceEvent: this.sourceEvent, + target: zoom, + type, + transform: this.that.__zoom, + dispatch: listeners + }), + d + ); + } + }; + + function wheeled(event, ...args) { + if (!filter.apply(this, arguments)) return; + var g = gesture(this, args).event(event), + t = this.__zoom, + k = Math.max(scaleExtent[0], Math.min(scaleExtent[1], t.k * Math.pow(2, wheelDelta.apply(this, arguments)))), + p = pointer(event); + + // If the mouse is in the same location as before, reuse it. + // If there were recent wheel events, reset the wheel idle timeout. + if (g.wheel) { + if (g.mouse[0][0] !== p[0] || g.mouse[0][1] !== p[1]) { + g.mouse[1] = t.invert(g.mouse[0] = p); + } + clearTimeout(g.wheel); + } + + // If this wheel event won’t trigger a transform change, ignore it. + else if (t.k === k) return; + + // Otherwise, capture the mouse point and location at the start. + else { + g.mouse = [p, t.invert(p)]; + interrupt(this); + g.start(); + } + + noevent(event); + g.wheel = setTimeout(wheelidled, wheelDelay); + g.zoom("mouse", constrain(translate(scale(t, k), g.mouse[0], g.mouse[1]), g.extent, translateExtent)); + + function wheelidled() { + g.wheel = null; + g.end(); + } + } + + function mousedowned(event, ...args) { + if (touchending || !filter.apply(this, arguments)) return; + var currentTarget = event.currentTarget, + g = gesture(this, args, true).event(event), + v = d3Select(event.view).on("mousemove.zoom", mousemoved, true).on("mouseup.zoom", mouseupped, true), + p = pointer(event, currentTarget), + x0 = event.clientX, + y0 = event.clientY; + + dragDisable(event.view); + nopropagation(event); + g.mouse = [p, this.__zoom.invert(p)]; + interrupt(this); + g.start(); + + function mousemoved(event) { + noevent(event); + if (!g.moved) { + var dx = event.clientX - x0, dy = event.clientY - y0; + g.moved = dx * dx + dy * dy > clickDistance2; + } + g.event(event) + .zoom("mouse", constrain(translate(g.that.__zoom, g.mouse[0] = pointer(event, currentTarget), g.mouse[1]), g.extent, translateExtent)); + } + + function mouseupped(event) { + v.on("mousemove.zoom mouseup.zoom", null); + yesdrag(event.view, g.moved); + noevent(event); + g.event(event).end(); + } + } + + function dblclicked(event, ...args) { + if (!filter.apply(this, arguments)) return; + var t0 = this.__zoom, + p0 = pointer(event.changedTouches ? event.changedTouches[0] : event, this), + p1 = t0.invert(p0), + k1 = t0.k * (event.shiftKey ? 0.5 : 2), + t1 = constrain(translate(scale(t0, k1), p0, p1), extent.apply(this, args), translateExtent); + + noevent(event); + if (duration > 0) d3Select(this).transition().duration(duration).call(schedule, t1, p0, event); + else d3Select(this).call(zoom.transform, t1, p0, event); + } + + function touchstarted(event, ...args) { + if (!filter.apply(this, arguments)) return; + var touches = event.touches, + n = touches.length, + g = gesture(this, args, event.changedTouches.length === n).event(event), + started, i, t, p; + + nopropagation(event); + for (i = 0; i < n; ++i) { + t = touches[i], p = pointer(t, this); + p = [p, this.__zoom.invert(p), t.identifier]; + if (!g.touch0) g.touch0 = p, started = true, g.taps = 1 + !!touchstarting; + else if (!g.touch1 && g.touch0[2] !== p[2]) g.touch1 = p, g.taps = 0; + } + + if (touchstarting) touchstarting = clearTimeout(touchstarting); + + if (started) { + if (g.taps < 2) touchfirst = p[0], touchstarting = setTimeout(function() { touchstarting = null; }, touchDelay); + interrupt(this); + g.start(); + } + } + + function touchmoved(event, ...args) { + if (!this.__zooming) return; + var g = gesture(this, args).event(event), + touches = event.changedTouches, + n = touches.length, i, t, p, l; + + noevent(event); + for (i = 0; i < n; ++i) { + t = touches[i], p = pointer(t, this); + if (g.touch0 && g.touch0[2] === t.identifier) g.touch0[0] = p; + else if (g.touch1 && g.touch1[2] === t.identifier) g.touch1[0] = p; + } + t = g.that.__zoom; + if (g.touch1) { + var p0 = g.touch0[0], l0 = g.touch0[1], + p1 = g.touch1[0], l1 = g.touch1[1], + dp = (dp = p1[0] - p0[0]) * dp + (dp = p1[1] - p0[1]) * dp, + dl = (dl = l1[0] - l0[0]) * dl + (dl = l1[1] - l0[1]) * dl; + t = scale(t, Math.sqrt(dp / dl)); + p = [(p0[0] + p1[0]) / 2, (p0[1] + p1[1]) / 2]; + l = [(l0[0] + l1[0]) / 2, (l0[1] + l1[1]) / 2]; + } + else if (g.touch0) p = g.touch0[0], l = g.touch0[1]; + else return; + + g.zoom("touch", constrain(translate(t, p, l), g.extent, translateExtent)); + } + + function touchended(event, ...args) { + if (!this.__zooming) return; + var g = gesture(this, args).event(event), + touches = event.changedTouches, + n = touches.length, i, t; + + nopropagation(event); + if (touchending) clearTimeout(touchending); + touchending = setTimeout(function() { touchending = null; }, touchDelay); + for (i = 0; i < n; ++i) { + t = touches[i]; + if (g.touch0 && g.touch0[2] === t.identifier) delete g.touch0; + else if (g.touch1 && g.touch1[2] === t.identifier) delete g.touch1; + } + if (g.touch1 && !g.touch0) g.touch0 = g.touch1, delete g.touch1; + if (g.touch0) g.touch0[1] = this.__zoom.invert(g.touch0[0]); + else { + g.end(); + // If this was a dbltap, reroute to the (optional) dblclick.zoom handler. + if (g.taps === 2) { + t = pointer(t, this); + if (Math.hypot(touchfirst[0] - t[0], touchfirst[1] - t[1]) < tapDistance) { + var p = d3Select(this).on("dblclick.zoom"); + if (p) p.apply(this, arguments); + } + } + } + } + + zoom.wheelDelta = function(_) { + return arguments.length ? (wheelDelta = typeof _ === "function" ? _ : constant$1(+_), zoom) : wheelDelta; + }; + + zoom.filter = function(_) { + return arguments.length ? (filter = typeof _ === "function" ? _ : constant$1(!!_), zoom) : filter; + }; + + zoom.touchable = function(_) { + return arguments.length ? (touchable = typeof _ === "function" ? _ : constant$1(!!_), zoom) : touchable; + }; + + zoom.extent = function(_) { + return arguments.length ? (extent = typeof _ === "function" ? _ : constant$1([[+_[0][0], +_[0][1]], [+_[1][0], +_[1][1]]]), zoom) : extent; + }; + + zoom.scaleExtent = function(_) { + return arguments.length ? (scaleExtent[0] = +_[0], scaleExtent[1] = +_[1], zoom) : [scaleExtent[0], scaleExtent[1]]; + }; + + zoom.translateExtent = function(_) { + return arguments.length ? (translateExtent[0][0] = +_[0][0], translateExtent[1][0] = +_[1][0], translateExtent[0][1] = +_[0][1], translateExtent[1][1] = +_[1][1], zoom) : [[translateExtent[0][0], translateExtent[0][1]], [translateExtent[1][0], translateExtent[1][1]]]; + }; + + zoom.constrain = function(_) { + return arguments.length ? (constrain = _, zoom) : constrain; + }; + + zoom.duration = function(_) { + return arguments.length ? (duration = +_, zoom) : duration; + }; + + zoom.interpolate = function(_) { + return arguments.length ? (interpolate = _, zoom) : interpolate; + }; + + zoom.on = function() { + var value = listeners.on.apply(listeners, arguments); + return value === listeners ? zoom : value; + }; + + zoom.clickDistance = function(_) { + return arguments.length ? (clickDistance2 = (_ = +_) * _, zoom) : Math.sqrt(clickDistance2); + }; + + zoom.tapDistance = function(_) { + return arguments.length ? (tapDistance = +_, zoom) : tapDistance; + }; + + return zoom; + } + + class InternMap extends Map { + constructor(entries, key = keyof) { + super(); + Object.defineProperties(this, {_intern: {value: new Map()}, _key: {value: key}}); + if (entries != null) for (const [key, value] of entries) this.set(key, value); + } + get(key) { + return super.get(intern_get(this, key)); + } + has(key) { + return super.has(intern_get(this, key)); + } + set(key, value) { + return super.set(intern_set(this, key), value); + } + delete(key) { + return super.delete(intern_delete(this, key)); + } + } + + function intern_get({_intern, _key}, value) { + const key = _key(value); + return _intern.has(key) ? _intern.get(key) : value; + } + + function intern_set({_intern, _key}, value) { + const key = _key(value); + if (_intern.has(key)) return _intern.get(key); + _intern.set(key, value); + return value; + } + + function intern_delete({_intern, _key}, value) { + const key = _key(value); + if (_intern.has(key)) { + value = _intern.get(key); + _intern.delete(key); + } + return value; + } + + function keyof(value) { + return value !== null && typeof value === "object" ? value.valueOf() : value; + } + + function max$1(values, valueof) { + let max; + if (valueof === undefined) { + for (const value of values) { + if (value != null + && (max < value || (max === undefined && value >= value))) { + max = value; + } + } + } else { + let index = -1; + for (let value of values) { + if ((value = valueof(value, ++index, values)) != null + && (max < value || (max === undefined && value >= value))) { + max = value; + } + } + } + return max; + } + + function min$1(values, valueof) { + let min; + if (valueof === undefined) { + for (const value of values) { + if (value != null + && (min > value || (min === undefined && value >= value))) { + min = value; + } + } + } else { + let index = -1; + for (let value of values) { + if ((value = valueof(value, ++index, values)) != null + && (min > value || (min === undefined && value >= value))) { + min = value; + } + } + } + return min; + } + + /** Detect free variable `global` from Node.js. */ + var freeGlobal = typeof global == 'object' && global && global.Object === Object && global; + + var freeGlobal$1 = freeGlobal; + + /** Detect free variable `self`. */ + var freeSelf = typeof self == 'object' && self && self.Object === Object && self; + + /** Used as a reference to the global object. */ + var root = freeGlobal$1 || freeSelf || Function('return this')(); + + var root$1 = root; + + /** Built-in value references. */ + var Symbol$1 = root$1.Symbol; + + var Symbol$2 = Symbol$1; + + /** Used for built-in method references. */ + var objectProto$1 = Object.prototype; + + /** Used to check objects for own properties. */ + var hasOwnProperty = objectProto$1.hasOwnProperty; + + /** + * Used to resolve the + * [`toStringTag`](http://ecma-international.org/ecma-262/7.0/#sec-object.prototype.tostring) + * of values. + */ + var nativeObjectToString$1 = objectProto$1.toString; + + /** Built-in value references. */ + var symToStringTag$1 = Symbol$2 ? Symbol$2.toStringTag : undefined; + + /** + * A specialized version of `baseGetTag` which ignores `Symbol.toStringTag` values. + * + * @private + * @param {*} value The value to query. + * @returns {string} Returns the raw `toStringTag`. + */ + function getRawTag(value) { + var isOwn = hasOwnProperty.call(value, symToStringTag$1), + tag = value[symToStringTag$1]; + + try { + value[symToStringTag$1] = undefined; + var unmasked = true; + } catch (e) {} + + var result = nativeObjectToString$1.call(value); + if (unmasked) { + if (isOwn) { + value[symToStringTag$1] = tag; + } else { + delete value[symToStringTag$1]; + } + } + return result; + } + + /** Used for built-in method references. */ + var objectProto = Object.prototype; + + /** + * Used to resolve the + * [`toStringTag`](http://ecma-international.org/ecma-262/7.0/#sec-object.prototype.tostring) + * of values. + */ + var nativeObjectToString = objectProto.toString; + + /** + * Converts `value` to a string using `Object.prototype.toString`. + * + * @private + * @param {*} value The value to convert. + * @returns {string} Returns the converted string. + */ + function objectToString(value) { + return nativeObjectToString.call(value); + } + + /** `Object#toString` result references. */ + var nullTag = '[object Null]', + undefinedTag = '[object Undefined]'; + + /** Built-in value references. */ + var symToStringTag = Symbol$2 ? Symbol$2.toStringTag : undefined; + + /** + * The base implementation of `getTag` without fallbacks for buggy environments. + * + * @private + * @param {*} value The value to query. + * @returns {string} Returns the `toStringTag`. + */ + function baseGetTag(value) { + if (value == null) { + return value === undefined ? undefinedTag : nullTag; + } + return (symToStringTag && symToStringTag in Object(value)) + ? getRawTag(value) + : objectToString(value); + } + + /** + * Checks if `value` is object-like. A value is object-like if it's not `null` + * and has a `typeof` result of "object". + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is object-like, else `false`. + * @example + * + * _.isObjectLike({}); + * // => true + * + * _.isObjectLike([1, 2, 3]); + * // => true + * + * _.isObjectLike(_.noop); + * // => false + * + * _.isObjectLike(null); + * // => false + */ + function isObjectLike(value) { + return value != null && typeof value == 'object'; + } + + /** `Object#toString` result references. */ + var symbolTag = '[object Symbol]'; + + /** + * Checks if `value` is classified as a `Symbol` primitive or object. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a symbol, else `false`. + * @example + * + * _.isSymbol(Symbol.iterator); + * // => true + * + * _.isSymbol('abc'); + * // => false + */ + function isSymbol(value) { + return typeof value == 'symbol' || + (isObjectLike(value) && baseGetTag(value) == symbolTag); + } + + /** Used to match a single whitespace character. */ + var reWhitespace = /\s/; + + /** + * Used by `_.trim` and `_.trimEnd` to get the index of the last non-whitespace + * character of `string`. + * + * @private + * @param {string} string The string to inspect. + * @returns {number} Returns the index of the last non-whitespace character. + */ + function trimmedEndIndex(string) { + var index = string.length; + + while (index-- && reWhitespace.test(string.charAt(index))) {} + return index; + } + + /** Used to match leading whitespace. */ + var reTrimStart = /^\s+/; + + /** + * The base implementation of `_.trim`. + * + * @private + * @param {string} string The string to trim. + * @returns {string} Returns the trimmed string. + */ + function baseTrim(string) { + return string + ? string.slice(0, trimmedEndIndex(string) + 1).replace(reTrimStart, '') + : string; + } + + /** + * Checks if `value` is the + * [language type](http://www.ecma-international.org/ecma-262/7.0/#sec-ecmascript-language-types) + * of `Object`. (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`) + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is an object, else `false`. + * @example + * + * _.isObject({}); + * // => true + * + * _.isObject([1, 2, 3]); + * // => true + * + * _.isObject(_.noop); + * // => true + * + * _.isObject(null); + * // => false + */ + function isObject(value) { + var type = typeof value; + return value != null && (type == 'object' || type == 'function'); + } + + /** Used as references for various `Number` constants. */ + var NAN = 0 / 0; + + /** Used to detect bad signed hexadecimal string values. */ + var reIsBadHex = /^[-+]0x[0-9a-f]+$/i; + + /** Used to detect binary string values. */ + var reIsBinary = /^0b[01]+$/i; + + /** Used to detect octal string values. */ + var reIsOctal = /^0o[0-7]+$/i; + + /** Built-in method references without a dependency on `root`. */ + var freeParseInt = parseInt; + + /** + * Converts `value` to a number. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Lang + * @param {*} value The value to process. + * @returns {number} Returns the number. + * @example + * + * _.toNumber(3.2); + * // => 3.2 + * + * _.toNumber(Number.MIN_VALUE); + * // => 5e-324 + * + * _.toNumber(Infinity); + * // => Infinity + * + * _.toNumber('3.2'); + * // => 3.2 + */ + function toNumber(value) { + if (typeof value == 'number') { + return value; + } + if (isSymbol(value)) { + return NAN; + } + if (isObject(value)) { + var other = typeof value.valueOf == 'function' ? value.valueOf() : value; + value = isObject(other) ? (other + '') : other; + } + if (typeof value != 'string') { + return value === 0 ? value : +value; + } + value = baseTrim(value); + var isBinary = reIsBinary.test(value); + return (isBinary || reIsOctal.test(value)) + ? freeParseInt(value.slice(2), isBinary ? 2 : 8) + : (reIsBadHex.test(value) ? NAN : +value); + } + + /** + * Gets the timestamp of the number of milliseconds that have elapsed since + * the Unix epoch (1 January 1970 00:00:00 UTC). + * + * @static + * @memberOf _ + * @since 2.4.0 + * @category Date + * @returns {number} Returns the timestamp. + * @example + * + * _.defer(function(stamp) { + * console.log(_.now() - stamp); + * }, _.now()); + * // => Logs the number of milliseconds it took for the deferred invocation. + */ + var now$1 = function() { + return root$1.Date.now(); + }; + + var now$2 = now$1; + + /** Error message constants. */ + var FUNC_ERROR_TEXT$1 = 'Expected a function'; + + /* Built-in method references for those with the same name as other `lodash` methods. */ + var nativeMax = Math.max, + nativeMin = Math.min; + + /** + * Creates a debounced function that delays invoking `func` until after `wait` + * milliseconds have elapsed since the last time the debounced function was + * invoked. The debounced function comes with a `cancel` method to cancel + * delayed `func` invocations and a `flush` method to immediately invoke them. + * Provide `options` to indicate whether `func` should be invoked on the + * leading and/or trailing edge of the `wait` timeout. The `func` is invoked + * with the last arguments provided to the debounced function. Subsequent + * calls to the debounced function return the result of the last `func` + * invocation. + * + * **Note:** If `leading` and `trailing` options are `true`, `func` is + * invoked on the trailing edge of the timeout only if the debounced function + * is invoked more than once during the `wait` timeout. + * + * If `wait` is `0` and `leading` is `false`, `func` invocation is deferred + * until to the next tick, similar to `setTimeout` with a timeout of `0`. + * + * See [David Corbacho's article](https://css-tricks.com/debouncing-throttling-explained-examples/) + * for details over the differences between `_.debounce` and `_.throttle`. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Function + * @param {Function} func The function to debounce. + * @param {number} [wait=0] The number of milliseconds to delay. + * @param {Object} [options={}] The options object. + * @param {boolean} [options.leading=false] + * Specify invoking on the leading edge of the timeout. + * @param {number} [options.maxWait] + * The maximum time `func` is allowed to be delayed before it's invoked. + * @param {boolean} [options.trailing=true] + * Specify invoking on the trailing edge of the timeout. + * @returns {Function} Returns the new debounced function. + * @example + * + * // Avoid costly calculations while the window size is in flux. + * jQuery(window).on('resize', _.debounce(calculateLayout, 150)); + * + * // Invoke `sendMail` when clicked, debouncing subsequent calls. + * jQuery(element).on('click', _.debounce(sendMail, 300, { + * 'leading': true, + * 'trailing': false + * })); + * + * // Ensure `batchLog` is invoked once after 1 second of debounced calls. + * var debounced = _.debounce(batchLog, 250, { 'maxWait': 1000 }); + * var source = new EventSource('/stream'); + * jQuery(source).on('message', debounced); + * + * // Cancel the trailing debounced invocation. + * jQuery(window).on('popstate', debounced.cancel); + */ + function debounce(func, wait, options) { + var lastArgs, + lastThis, + maxWait, + result, + timerId, + lastCallTime, + lastInvokeTime = 0, + leading = false, + maxing = false, + trailing = true; + + if (typeof func != 'function') { + throw new TypeError(FUNC_ERROR_TEXT$1); + } + wait = toNumber(wait) || 0; + if (isObject(options)) { + leading = !!options.leading; + maxing = 'maxWait' in options; + maxWait = maxing ? nativeMax(toNumber(options.maxWait) || 0, wait) : maxWait; + trailing = 'trailing' in options ? !!options.trailing : trailing; + } + + function invokeFunc(time) { + var args = lastArgs, + thisArg = lastThis; + + lastArgs = lastThis = undefined; + lastInvokeTime = time; + result = func.apply(thisArg, args); + return result; + } + + function leadingEdge(time) { + // Reset any `maxWait` timer. + lastInvokeTime = time; + // Start the timer for the trailing edge. + timerId = setTimeout(timerExpired, wait); + // Invoke the leading edge. + return leading ? invokeFunc(time) : result; + } + + function remainingWait(time) { + var timeSinceLastCall = time - lastCallTime, + timeSinceLastInvoke = time - lastInvokeTime, + timeWaiting = wait - timeSinceLastCall; + + return maxing + ? nativeMin(timeWaiting, maxWait - timeSinceLastInvoke) + : timeWaiting; + } + + function shouldInvoke(time) { + var timeSinceLastCall = time - lastCallTime, + timeSinceLastInvoke = time - lastInvokeTime; + + // Either this is the first call, activity has stopped and we're at the + // trailing edge, the system time has gone backwards and we're treating + // it as the trailing edge, or we've hit the `maxWait` limit. + return (lastCallTime === undefined || (timeSinceLastCall >= wait) || + (timeSinceLastCall < 0) || (maxing && timeSinceLastInvoke >= maxWait)); + } + + function timerExpired() { + var time = now$2(); + if (shouldInvoke(time)) { + return trailingEdge(time); + } + // Restart the timer. + timerId = setTimeout(timerExpired, remainingWait(time)); + } + + function trailingEdge(time) { + timerId = undefined; + + // Only invoke if we have `lastArgs` which means `func` has been + // debounced at least once. + if (trailing && lastArgs) { + return invokeFunc(time); + } + lastArgs = lastThis = undefined; + return result; + } + + function cancel() { + if (timerId !== undefined) { + clearTimeout(timerId); + } + lastInvokeTime = 0; + lastArgs = lastCallTime = lastThis = timerId = undefined; + } + + function flush() { + return timerId === undefined ? result : trailingEdge(now$2()); + } + + function debounced() { + var time = now$2(), + isInvoking = shouldInvoke(time); + + lastArgs = arguments; + lastThis = this; + lastCallTime = time; + + if (isInvoking) { + if (timerId === undefined) { + return leadingEdge(lastCallTime); + } + if (maxing) { + // Handle invocations in a tight loop. + clearTimeout(timerId); + timerId = setTimeout(timerExpired, wait); + return invokeFunc(lastCallTime); + } + } + if (timerId === undefined) { + timerId = setTimeout(timerExpired, wait); + } + return result; + } + debounced.cancel = cancel; + debounced.flush = flush; + return debounced; + } + + /** Error message constants. */ + var FUNC_ERROR_TEXT = 'Expected a function'; + + /** + * Creates a throttled function that only invokes `func` at most once per + * every `wait` milliseconds. The throttled function comes with a `cancel` + * method to cancel delayed `func` invocations and a `flush` method to + * immediately invoke them. Provide `options` to indicate whether `func` + * should be invoked on the leading and/or trailing edge of the `wait` + * timeout. The `func` is invoked with the last arguments provided to the + * throttled function. Subsequent calls to the throttled function return the + * result of the last `func` invocation. + * + * **Note:** If `leading` and `trailing` options are `true`, `func` is + * invoked on the trailing edge of the timeout only if the throttled function + * is invoked more than once during the `wait` timeout. + * + * If `wait` is `0` and `leading` is `false`, `func` invocation is deferred + * until to the next tick, similar to `setTimeout` with a timeout of `0`. + * + * See [David Corbacho's article](https://css-tricks.com/debouncing-throttling-explained-examples/) + * for details over the differences between `_.throttle` and `_.debounce`. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Function + * @param {Function} func The function to throttle. + * @param {number} [wait=0] The number of milliseconds to throttle invocations to. + * @param {Object} [options={}] The options object. + * @param {boolean} [options.leading=true] + * Specify invoking on the leading edge of the timeout. + * @param {boolean} [options.trailing=true] + * Specify invoking on the trailing edge of the timeout. + * @returns {Function} Returns the new throttled function. + * @example + * + * // Avoid excessively updating the position while scrolling. + * jQuery(window).on('scroll', _.throttle(updatePosition, 100)); + * + * // Invoke `renewToken` when the click event is fired, but not more than once every 5 minutes. + * var throttled = _.throttle(renewToken, 300000, { 'trailing': false }); + * jQuery(element).on('click', throttled); + * + * // Cancel the trailing throttled invocation. + * jQuery(window).on('popstate', throttled.cancel); + */ + function throttle(func, wait, options) { + var leading = true, + trailing = true; + + if (typeof func != 'function') { + throw new TypeError(FUNC_ERROR_TEXT); + } + if (isObject(options)) { + leading = 'leading' in options ? !!options.leading : leading; + trailing = 'trailing' in options ? !!options.trailing : trailing; + } + return debounce(func, wait, { + 'leading': leading, + 'maxWait': wait, + 'trailing': trailing + }); + } + + /** + * The Ease class provides a collection of easing functions for use with tween.js. + */ + var Easing = Object.freeze({ + Linear: Object.freeze({ + None: function (amount) { + return amount; + }, + In: function (amount) { + return this.None(amount); + }, + Out: function (amount) { + return this.None(amount); + }, + InOut: function (amount) { + return this.None(amount); + }, + }), + Quadratic: Object.freeze({ + In: function (amount) { + return amount * amount; + }, + Out: function (amount) { + return amount * (2 - amount); + }, + InOut: function (amount) { + if ((amount *= 2) < 1) { + return 0.5 * amount * amount; + } + return -0.5 * (--amount * (amount - 2) - 1); + }, + }), + Cubic: Object.freeze({ + In: function (amount) { + return amount * amount * amount; + }, + Out: function (amount) { + return --amount * amount * amount + 1; + }, + InOut: function (amount) { + if ((amount *= 2) < 1) { + return 0.5 * amount * amount * amount; + } + return 0.5 * ((amount -= 2) * amount * amount + 2); + }, + }), + Quartic: Object.freeze({ + In: function (amount) { + return amount * amount * amount * amount; + }, + Out: function (amount) { + return 1 - --amount * amount * amount * amount; + }, + InOut: function (amount) { + if ((amount *= 2) < 1) { + return 0.5 * amount * amount * amount * amount; + } + return -0.5 * ((amount -= 2) * amount * amount * amount - 2); + }, + }), + Quintic: Object.freeze({ + In: function (amount) { + return amount * amount * amount * amount * amount; + }, + Out: function (amount) { + return --amount * amount * amount * amount * amount + 1; + }, + InOut: function (amount) { + if ((amount *= 2) < 1) { + return 0.5 * amount * amount * amount * amount * amount; + } + return 0.5 * ((amount -= 2) * amount * amount * amount * amount + 2); + }, + }), + Sinusoidal: Object.freeze({ + In: function (amount) { + return 1 - Math.sin(((1.0 - amount) * Math.PI) / 2); + }, + Out: function (amount) { + return Math.sin((amount * Math.PI) / 2); + }, + InOut: function (amount) { + return 0.5 * (1 - Math.sin(Math.PI * (0.5 - amount))); + }, + }), + Exponential: Object.freeze({ + In: function (amount) { + return amount === 0 ? 0 : Math.pow(1024, amount - 1); + }, + Out: function (amount) { + return amount === 1 ? 1 : 1 - Math.pow(2, -10 * amount); + }, + InOut: function (amount) { + if (amount === 0) { + return 0; + } + if (amount === 1) { + return 1; + } + if ((amount *= 2) < 1) { + return 0.5 * Math.pow(1024, amount - 1); + } + return 0.5 * (-Math.pow(2, -10 * (amount - 1)) + 2); + }, + }), + Circular: Object.freeze({ + In: function (amount) { + return 1 - Math.sqrt(1 - amount * amount); + }, + Out: function (amount) { + return Math.sqrt(1 - --amount * amount); + }, + InOut: function (amount) { + if ((amount *= 2) < 1) { + return -0.5 * (Math.sqrt(1 - amount * amount) - 1); + } + return 0.5 * (Math.sqrt(1 - (amount -= 2) * amount) + 1); + }, + }), + Elastic: Object.freeze({ + In: function (amount) { + if (amount === 0) { + return 0; + } + if (amount === 1) { + return 1; + } + return -Math.pow(2, 10 * (amount - 1)) * Math.sin((amount - 1.1) * 5 * Math.PI); + }, + Out: function (amount) { + if (amount === 0) { + return 0; + } + if (amount === 1) { + return 1; + } + return Math.pow(2, -10 * amount) * Math.sin((amount - 0.1) * 5 * Math.PI) + 1; + }, + InOut: function (amount) { + if (amount === 0) { + return 0; + } + if (amount === 1) { + return 1; + } + amount *= 2; + if (amount < 1) { + return -0.5 * Math.pow(2, 10 * (amount - 1)) * Math.sin((amount - 1.1) * 5 * Math.PI); + } + return 0.5 * Math.pow(2, -10 * (amount - 1)) * Math.sin((amount - 1.1) * 5 * Math.PI) + 1; + }, + }), + Back: Object.freeze({ + In: function (amount) { + var s = 1.70158; + return amount === 1 ? 1 : amount * amount * ((s + 1) * amount - s); + }, + Out: function (amount) { + var s = 1.70158; + return amount === 0 ? 0 : --amount * amount * ((s + 1) * amount + s) + 1; + }, + InOut: function (amount) { + var s = 1.70158 * 1.525; + if ((amount *= 2) < 1) { + return 0.5 * (amount * amount * ((s + 1) * amount - s)); + } + return 0.5 * ((amount -= 2) * amount * ((s + 1) * amount + s) + 2); + }, + }), + Bounce: Object.freeze({ + In: function (amount) { + return 1 - Easing.Bounce.Out(1 - amount); + }, + Out: function (amount) { + if (amount < 1 / 2.75) { + return 7.5625 * amount * amount; + } + else if (amount < 2 / 2.75) { + return 7.5625 * (amount -= 1.5 / 2.75) * amount + 0.75; + } + else if (amount < 2.5 / 2.75) { + return 7.5625 * (amount -= 2.25 / 2.75) * amount + 0.9375; + } + else { + return 7.5625 * (amount -= 2.625 / 2.75) * amount + 0.984375; + } + }, + InOut: function (amount) { + if (amount < 0.5) { + return Easing.Bounce.In(amount * 2) * 0.5; + } + return Easing.Bounce.Out(amount * 2 - 1) * 0.5 + 0.5; + }, + }), + generatePow: function (power) { + if (power === void 0) { power = 4; } + power = power < Number.EPSILON ? Number.EPSILON : power; + power = power > 10000 ? 10000 : power; + return { + In: function (amount) { + return Math.pow(amount, power); + }, + Out: function (amount) { + return 1 - Math.pow((1 - amount), power); + }, + InOut: function (amount) { + if (amount < 0.5) { + return Math.pow((amount * 2), power) / 2; + } + return (1 - Math.pow((2 - amount * 2), power)) / 2 + 0.5; + }, + }; + }, + }); + + var now = function () { return performance.now(); }; + + /** + * Controlling groups of tweens + * + * Using the TWEEN singleton to manage your tweens can cause issues in large apps with many components. + * In these cases, you may want to create your own smaller groups of tween + */ + var Group = /** @class */ (function () { + function Group() { + this._tweens = {}; + this._tweensAddedDuringUpdate = {}; + } + Group.prototype.getAll = function () { + var _this = this; + return Object.keys(this._tweens).map(function (tweenId) { + return _this._tweens[tweenId]; + }); + }; + Group.prototype.removeAll = function () { + this._tweens = {}; + }; + Group.prototype.add = function (tween) { + this._tweens[tween.getId()] = tween; + this._tweensAddedDuringUpdate[tween.getId()] = tween; + }; + Group.prototype.remove = function (tween) { + delete this._tweens[tween.getId()]; + delete this._tweensAddedDuringUpdate[tween.getId()]; + }; + Group.prototype.update = function (time, preserve) { + if (time === void 0) { time = now(); } + if (preserve === void 0) { preserve = false; } + var tweenIds = Object.keys(this._tweens); + if (tweenIds.length === 0) { + return false; + } + // Tweens are updated in "batches". If you add a new tween during an + // update, then the new tween will be updated in the next batch. + // If you remove a tween during an update, it may or may not be updated. + // However, if the removed tween was added during the current batch, + // then it will not be updated. + while (tweenIds.length > 0) { + this._tweensAddedDuringUpdate = {}; + for (var i = 0; i < tweenIds.length; i++) { + var tween = this._tweens[tweenIds[i]]; + var autoStart = !preserve; + if (tween && tween.update(time, autoStart) === false && !preserve) { + delete this._tweens[tweenIds[i]]; + } + } + tweenIds = Object.keys(this._tweensAddedDuringUpdate); + } + return true; + }; + return Group; + }()); + + /** + * + */ + var Interpolation = { + Linear: function (v, k) { + var m = v.length - 1; + var f = m * k; + var i = Math.floor(f); + var fn = Interpolation.Utils.Linear; + if (k < 0) { + return fn(v[0], v[1], f); + } + if (k > 1) { + return fn(v[m], v[m - 1], m - f); + } + return fn(v[i], v[i + 1 > m ? m : i + 1], f - i); + }, + Bezier: function (v, k) { + var b = 0; + var n = v.length - 1; + var pw = Math.pow; + var bn = Interpolation.Utils.Bernstein; + for (var i = 0; i <= n; i++) { + b += pw(1 - k, n - i) * pw(k, i) * v[i] * bn(n, i); + } + return b; + }, + CatmullRom: function (v, k) { + var m = v.length - 1; + var f = m * k; + var i = Math.floor(f); + var fn = Interpolation.Utils.CatmullRom; + if (v[0] === v[m]) { + if (k < 0) { + i = Math.floor((f = m * (1 + k))); + } + return fn(v[(i - 1 + m) % m], v[i], v[(i + 1) % m], v[(i + 2) % m], f - i); + } + else { + if (k < 0) { + return v[0] - (fn(v[0], v[0], v[1], v[1], -f) - v[0]); + } + if (k > 1) { + return v[m] - (fn(v[m], v[m], v[m - 1], v[m - 1], f - m) - v[m]); + } + return fn(v[i ? i - 1 : 0], v[i], v[m < i + 1 ? m : i + 1], v[m < i + 2 ? m : i + 2], f - i); + } + }, + Utils: { + Linear: function (p0, p1, t) { + return (p1 - p0) * t + p0; + }, + Bernstein: function (n, i) { + var fc = Interpolation.Utils.Factorial; + return fc(n) / fc(i) / fc(n - i); + }, + Factorial: (function () { + var a = [1]; + return function (n) { + var s = 1; + if (a[n]) { + return a[n]; + } + for (var i = n; i > 1; i--) { + s *= i; + } + a[n] = s; + return s; + }; + })(), + CatmullRom: function (p0, p1, p2, p3, t) { + var v0 = (p2 - p0) * 0.5; + var v1 = (p3 - p1) * 0.5; + var t2 = t * t; + var t3 = t * t2; + return (2 * p1 - 2 * p2 + v0 + v1) * t3 + (-3 * p1 + 3 * p2 - 2 * v0 - v1) * t2 + v0 * t + p1; + }, + }, + }; + + /** + * Utils + */ + var Sequence = /** @class */ (function () { + function Sequence() { + } + Sequence.nextId = function () { + return Sequence._nextId++; + }; + Sequence._nextId = 0; + return Sequence; + }()); + + var mainGroup = new Group(); + + /** + * Tween.js - Licensed under the MIT license + * https://github.com/tweenjs/tween.js + * ---------------------------------------------- + * + * See https://github.com/tweenjs/tween.js/graphs/contributors for the full list of contributors. + * Thank you all, you're awesome! + */ + var Tween = /** @class */ (function () { + function Tween(_object, _group) { + if (_group === void 0) { _group = mainGroup; } + this._object = _object; + this._group = _group; + this._isPaused = false; + this._pauseStart = 0; + this._valuesStart = {}; + this._valuesEnd = {}; + this._valuesStartRepeat = {}; + this._duration = 1000; + this._isDynamic = false; + this._initialRepeat = 0; + this._repeat = 0; + this._yoyo = false; + this._isPlaying = false; + this._reversed = false; + this._delayTime = 0; + this._startTime = 0; + this._easingFunction = Easing.Linear.None; + this._interpolationFunction = Interpolation.Linear; + // eslint-disable-next-line + this._chainedTweens = []; + this._onStartCallbackFired = false; + this._onEveryStartCallbackFired = false; + this._id = Sequence.nextId(); + this._isChainStopped = false; + this._propertiesAreSetUp = false; + this._goToEnd = false; + } + Tween.prototype.getId = function () { + return this._id; + }; + Tween.prototype.isPlaying = function () { + return this._isPlaying; + }; + Tween.prototype.isPaused = function () { + return this._isPaused; + }; + Tween.prototype.to = function (target, duration) { + if (duration === void 0) { duration = 1000; } + if (this._isPlaying) + throw new Error('Can not call Tween.to() while Tween is already started or paused. Stop the Tween first.'); + this._valuesEnd = target; + this._propertiesAreSetUp = false; + this._duration = duration; + return this; + }; + Tween.prototype.duration = function (duration) { + if (duration === void 0) { duration = 1000; } + this._duration = duration; + return this; + }; + Tween.prototype.dynamic = function (dynamic) { + if (dynamic === void 0) { dynamic = false; } + this._isDynamic = dynamic; + return this; + }; + Tween.prototype.start = function (time, overrideStartingValues) { + if (time === void 0) { time = now(); } + if (overrideStartingValues === void 0) { overrideStartingValues = false; } + if (this._isPlaying) { + return this; + } + // eslint-disable-next-line + this._group && this._group.add(this); + this._repeat = this._initialRepeat; + if (this._reversed) { + // If we were reversed (f.e. using the yoyo feature) then we need to + // flip the tween direction back to forward. + this._reversed = false; + for (var property in this._valuesStartRepeat) { + this._swapEndStartRepeatValues(property); + this._valuesStart[property] = this._valuesStartRepeat[property]; + } + } + this._isPlaying = true; + this._isPaused = false; + this._onStartCallbackFired = false; + this._onEveryStartCallbackFired = false; + this._isChainStopped = false; + this._startTime = time; + this._startTime += this._delayTime; + if (!this._propertiesAreSetUp || overrideStartingValues) { + this._propertiesAreSetUp = true; + // If dynamic is not enabled, clone the end values instead of using the passed-in end values. + if (!this._isDynamic) { + var tmp = {}; + for (var prop in this._valuesEnd) + tmp[prop] = this._valuesEnd[prop]; + this._valuesEnd = tmp; + } + this._setupProperties(this._object, this._valuesStart, this._valuesEnd, this._valuesStartRepeat, overrideStartingValues); + } + return this; + }; + Tween.prototype.startFromCurrentValues = function (time) { + return this.start(time, true); + }; + Tween.prototype._setupProperties = function (_object, _valuesStart, _valuesEnd, _valuesStartRepeat, overrideStartingValues) { + for (var property in _valuesEnd) { + var startValue = _object[property]; + var startValueIsArray = Array.isArray(startValue); + var propType = startValueIsArray ? 'array' : typeof startValue; + var isInterpolationList = !startValueIsArray && Array.isArray(_valuesEnd[property]); + // If `to()` specifies a property that doesn't exist in the source object, + // we should not set that property in the object + if (propType === 'undefined' || propType === 'function') { + continue; + } + // Check if an Array was provided as property value + if (isInterpolationList) { + var endValues = _valuesEnd[property]; + if (endValues.length === 0) { + continue; + } + // Handle an array of relative values. + // Creates a local copy of the Array with the start value at the front + var temp = [startValue]; + for (var i = 0, l = endValues.length; i < l; i += 1) { + var value = this._handleRelativeValue(startValue, endValues[i]); + if (isNaN(value)) { + isInterpolationList = false; + console.warn('Found invalid interpolation list. Skipping.'); + break; + } + temp.push(value); + } + if (isInterpolationList) { + // if (_valuesStart[property] === undefined) { // handle end values only the first time. NOT NEEDED? setupProperties is now guarded by _propertiesAreSetUp. + _valuesEnd[property] = temp; + // } + } + } + // handle the deepness of the values + if ((propType === 'object' || startValueIsArray) && startValue && !isInterpolationList) { + _valuesStart[property] = startValueIsArray ? [] : {}; + var nestedObject = startValue; + for (var prop in nestedObject) { + _valuesStart[property][prop] = nestedObject[prop]; + } + // TODO? repeat nested values? And yoyo? And array values? + _valuesStartRepeat[property] = startValueIsArray ? [] : {}; + var endValues = _valuesEnd[property]; + // If dynamic is not enabled, clone the end values instead of using the passed-in end values. + if (!this._isDynamic) { + var tmp = {}; + for (var prop in endValues) + tmp[prop] = endValues[prop]; + _valuesEnd[property] = endValues = tmp; + } + this._setupProperties(nestedObject, _valuesStart[property], endValues, _valuesStartRepeat[property], overrideStartingValues); + } + else { + // Save the starting value, but only once unless override is requested. + if (typeof _valuesStart[property] === 'undefined' || overrideStartingValues) { + _valuesStart[property] = startValue; + } + if (!startValueIsArray) { + // eslint-disable-next-line + // @ts-ignore FIXME? + _valuesStart[property] *= 1.0; // Ensures we're using numbers, not strings + } + if (isInterpolationList) { + // eslint-disable-next-line + // @ts-ignore FIXME? + _valuesStartRepeat[property] = _valuesEnd[property].slice().reverse(); + } + else { + _valuesStartRepeat[property] = _valuesStart[property] || 0; + } + } + } + }; + Tween.prototype.stop = function () { + if (!this._isChainStopped) { + this._isChainStopped = true; + this.stopChainedTweens(); + } + if (!this._isPlaying) { + return this; + } + // eslint-disable-next-line + this._group && this._group.remove(this); + this._isPlaying = false; + this._isPaused = false; + if (this._onStopCallback) { + this._onStopCallback(this._object); + } + return this; + }; + Tween.prototype.end = function () { + this._goToEnd = true; + this.update(Infinity); + return this; + }; + Tween.prototype.pause = function (time) { + if (time === void 0) { time = now(); } + if (this._isPaused || !this._isPlaying) { + return this; + } + this._isPaused = true; + this._pauseStart = time; + // eslint-disable-next-line + this._group && this._group.remove(this); + return this; + }; + Tween.prototype.resume = function (time) { + if (time === void 0) { time = now(); } + if (!this._isPaused || !this._isPlaying) { + return this; + } + this._isPaused = false; + this._startTime += time - this._pauseStart; + this._pauseStart = 0; + // eslint-disable-next-line + this._group && this._group.add(this); + return this; + }; + Tween.prototype.stopChainedTweens = function () { + for (var i = 0, numChainedTweens = this._chainedTweens.length; i < numChainedTweens; i++) { + this._chainedTweens[i].stop(); + } + return this; + }; + Tween.prototype.group = function (group) { + if (group === void 0) { group = mainGroup; } + this._group = group; + return this; + }; + Tween.prototype.delay = function (amount) { + if (amount === void 0) { amount = 0; } + this._delayTime = amount; + return this; + }; + Tween.prototype.repeat = function (times) { + if (times === void 0) { times = 0; } + this._initialRepeat = times; + this._repeat = times; + return this; + }; + Tween.prototype.repeatDelay = function (amount) { + this._repeatDelayTime = amount; + return this; + }; + Tween.prototype.yoyo = function (yoyo) { + if (yoyo === void 0) { yoyo = false; } + this._yoyo = yoyo; + return this; + }; + Tween.prototype.easing = function (easingFunction) { + if (easingFunction === void 0) { easingFunction = Easing.Linear.None; } + this._easingFunction = easingFunction; + return this; + }; + Tween.prototype.interpolation = function (interpolationFunction) { + if (interpolationFunction === void 0) { interpolationFunction = Interpolation.Linear; } + this._interpolationFunction = interpolationFunction; + return this; + }; + // eslint-disable-next-line + Tween.prototype.chain = function () { + var tweens = []; + for (var _i = 0; _i < arguments.length; _i++) { + tweens[_i] = arguments[_i]; + } + this._chainedTweens = tweens; + return this; + }; + Tween.prototype.onStart = function (callback) { + this._onStartCallback = callback; + return this; + }; + Tween.prototype.onEveryStart = function (callback) { + this._onEveryStartCallback = callback; + return this; + }; + Tween.prototype.onUpdate = function (callback) { + this._onUpdateCallback = callback; + return this; + }; + Tween.prototype.onRepeat = function (callback) { + this._onRepeatCallback = callback; + return this; + }; + Tween.prototype.onComplete = function (callback) { + this._onCompleteCallback = callback; + return this; + }; + Tween.prototype.onStop = function (callback) { + this._onStopCallback = callback; + return this; + }; + /** + * @returns true if the tween is still playing after the update, false + * otherwise (calling update on a paused tween still returns true because + * it is still playing, just paused). + */ + Tween.prototype.update = function (time, autoStart) { + if (time === void 0) { time = now(); } + if (autoStart === void 0) { autoStart = true; } + if (this._isPaused) + return true; + var property; + var elapsed; + var endTime = this._startTime + this._duration; + if (!this._goToEnd && !this._isPlaying) { + if (time > endTime) + return false; + if (autoStart) + this.start(time, true); + } + this._goToEnd = false; + if (time < this._startTime) { + return true; + } + if (this._onStartCallbackFired === false) { + if (this._onStartCallback) { + this._onStartCallback(this._object); + } + this._onStartCallbackFired = true; + } + if (this._onEveryStartCallbackFired === false) { + if (this._onEveryStartCallback) { + this._onEveryStartCallback(this._object); + } + this._onEveryStartCallbackFired = true; + } + elapsed = (time - this._startTime) / this._duration; + elapsed = this._duration === 0 || elapsed > 1 ? 1 : elapsed; + var value = this._easingFunction(elapsed); + // properties transformations + this._updateProperties(this._object, this._valuesStart, this._valuesEnd, value); + if (this._onUpdateCallback) { + this._onUpdateCallback(this._object, elapsed); + } + if (elapsed === 1) { + if (this._repeat > 0) { + if (isFinite(this._repeat)) { + this._repeat--; + } + // Reassign starting values, restart by making startTime = now + for (property in this._valuesStartRepeat) { + if (!this._yoyo && typeof this._valuesEnd[property] === 'string') { + this._valuesStartRepeat[property] = + // eslint-disable-next-line + // @ts-ignore FIXME? + this._valuesStartRepeat[property] + parseFloat(this._valuesEnd[property]); + } + if (this._yoyo) { + this._swapEndStartRepeatValues(property); + } + this._valuesStart[property] = this._valuesStartRepeat[property]; + } + if (this._yoyo) { + this._reversed = !this._reversed; + } + if (this._repeatDelayTime !== undefined) { + this._startTime = time + this._repeatDelayTime; + } + else { + this._startTime = time + this._delayTime; + } + if (this._onRepeatCallback) { + this._onRepeatCallback(this._object); + } + this._onEveryStartCallbackFired = false; + return true; + } + else { + if (this._onCompleteCallback) { + this._onCompleteCallback(this._object); + } + for (var i = 0, numChainedTweens = this._chainedTweens.length; i < numChainedTweens; i++) { + // Make the chained tweens start exactly at the time they should, + // even if the `update()` method was called way past the duration of the tween + this._chainedTweens[i].start(this._startTime + this._duration, false); + } + this._isPlaying = false; + return false; + } + } + return true; + }; + Tween.prototype._updateProperties = function (_object, _valuesStart, _valuesEnd, value) { + for (var property in _valuesEnd) { + // Don't update properties that do not exist in the source object + if (_valuesStart[property] === undefined) { + continue; + } + var start = _valuesStart[property] || 0; + var end = _valuesEnd[property]; + var startIsArray = Array.isArray(_object[property]); + var endIsArray = Array.isArray(end); + var isInterpolationList = !startIsArray && endIsArray; + if (isInterpolationList) { + _object[property] = this._interpolationFunction(end, value); + } + else if (typeof end === 'object' && end) { + // eslint-disable-next-line + // @ts-ignore FIXME? + this._updateProperties(_object[property], start, end, value); + } + else { + // Parses relative end values with start as base (e.g.: +10, -3) + end = this._handleRelativeValue(start, end); + // Protect against non numeric properties. + if (typeof end === 'number') { + // eslint-disable-next-line + // @ts-ignore FIXME? + _object[property] = start + (end - start) * value; + } + } + } + }; + Tween.prototype._handleRelativeValue = function (start, end) { + if (typeof end !== 'string') { + return end; + } + if (end.charAt(0) === '+' || end.charAt(0) === '-') { + return start + parseFloat(end); + } + return parseFloat(end); + }; + Tween.prototype._swapEndStartRepeatValues = function (property) { + var tmp = this._valuesStartRepeat[property]; + var endValue = this._valuesEnd[property]; + if (typeof endValue === 'string') { + this._valuesStartRepeat[property] = this._valuesStartRepeat[property] + parseFloat(endValue); + } + else { + this._valuesStartRepeat[property] = this._valuesEnd[property]; + } + this._valuesEnd[property] = tmp; + }; + return Tween; + }()); + /** + * Controlling groups of tweens + * + * Using the TWEEN singleton to manage your tweens can cause issues in large apps with many components. + * In these cases, you may want to create your own smaller groups of tweens. + */ + var TWEEN = mainGroup; + // This is the best way to export things in a way that's compatible with both ES + // Modules and CommonJS, without build hacks, and so as not to break the + // existing API. + // https://github.com/rollup/rollup/issues/1961#issuecomment-423037881 + TWEEN.getAll.bind(TWEEN); + TWEEN.removeAll.bind(TWEEN); + TWEEN.add.bind(TWEEN); + TWEEN.remove.bind(TWEEN); + var update = TWEEN.update.bind(TWEEN); + + function _iterableToArrayLimit$1(arr, i) { + var _i = null == arr ? null : "undefined" != typeof Symbol && arr[Symbol.iterator] || arr["@@iterator"]; + if (null != _i) { + var _s, + _e, + _x, + _r, + _arr = [], + _n = !0, + _d = !1; + try { + if (_x = (_i = _i.call(arr)).next, 0 === i) { + if (Object(_i) !== _i) return; + _n = !1; + } else for (; !(_n = (_s = _x.call(_i)).done) && (_arr.push(_s.value), _arr.length !== i); _n = !0); + } catch (err) { + _d = !0, _e = err; + } finally { + try { + if (!_n && null != _i.return && (_r = _i.return(), Object(_r) !== _r)) return; + } finally { + if (_d) throw _e; + } + } + return _arr; + } + } + function _classCallCheck$1(instance, Constructor) { + if (!(instance instanceof Constructor)) { + throw new TypeError("Cannot call a class as a function"); + } + } + function _defineProperties$1(target, props) { + for (var i = 0; i < props.length; i++) { + var descriptor = props[i]; + descriptor.enumerable = descriptor.enumerable || false; + descriptor.configurable = true; + if ("value" in descriptor) descriptor.writable = true; + Object.defineProperty(target, _toPropertyKey$2(descriptor.key), descriptor); + } + } + function _createClass$1(Constructor, protoProps, staticProps) { + if (protoProps) _defineProperties$1(Constructor.prototype, protoProps); + if (staticProps) _defineProperties$1(Constructor, staticProps); + Object.defineProperty(Constructor, "prototype", { + writable: false + }); + return Constructor; + } + function _slicedToArray$1(arr, i) { + return _arrayWithHoles$1(arr) || _iterableToArrayLimit$1(arr, i) || _unsupportedIterableToArray$2(arr, i) || _nonIterableRest$1(); + } + function _arrayWithHoles$1(arr) { + if (Array.isArray(arr)) return arr; + } + function _unsupportedIterableToArray$2(o, minLen) { + if (!o) return; + if (typeof o === "string") return _arrayLikeToArray$2(o, minLen); + var n = Object.prototype.toString.call(o).slice(8, -1); + if (n === "Object" && o.constructor) n = o.constructor.name; + if (n === "Map" || n === "Set") return Array.from(o); + if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray$2(o, minLen); + } + function _arrayLikeToArray$2(arr, len) { + if (len == null || len > arr.length) len = arr.length; + for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i]; + return arr2; + } + function _nonIterableRest$1() { + throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); + } + function _toPrimitive$2(input, hint) { + if (typeof input !== "object" || input === null) return input; + var prim = input[Symbol.toPrimitive]; + if (prim !== undefined) { + var res = prim.call(input, hint || "default"); + if (typeof res !== "object") return res; + throw new TypeError("@@toPrimitive must return a primitive value."); + } + return (hint === "string" ? String : Number)(input); + } + function _toPropertyKey$2(arg) { + var key = _toPrimitive$2(arg, "string"); + return typeof key === "symbol" ? key : String(key); + } + + var Prop = /*#__PURE__*/_createClass$1(function Prop(name, _ref) { + var _ref$default = _ref["default"], + defaultVal = _ref$default === void 0 ? null : _ref$default, + _ref$triggerUpdate = _ref.triggerUpdate, + triggerUpdate = _ref$triggerUpdate === void 0 ? true : _ref$triggerUpdate, + _ref$onChange = _ref.onChange, + onChange = _ref$onChange === void 0 ? function (newVal, state) {} : _ref$onChange; + _classCallCheck$1(this, Prop); + this.name = name; + this.defaultVal = defaultVal; + this.triggerUpdate = triggerUpdate; + this.onChange = onChange; + }); + function index$3 (_ref2) { + var _ref2$stateInit = _ref2.stateInit, + stateInit = _ref2$stateInit === void 0 ? function () { + return {}; + } : _ref2$stateInit, + _ref2$props = _ref2.props, + rawProps = _ref2$props === void 0 ? {} : _ref2$props, + _ref2$methods = _ref2.methods, + methods = _ref2$methods === void 0 ? {} : _ref2$methods, + _ref2$aliases = _ref2.aliases, + aliases = _ref2$aliases === void 0 ? {} : _ref2$aliases, + _ref2$init = _ref2.init, + initFn = _ref2$init === void 0 ? function () {} : _ref2$init, + _ref2$update = _ref2.update, + updateFn = _ref2$update === void 0 ? function () {} : _ref2$update; + // Parse props into Prop instances + var props = Object.keys(rawProps).map(function (propName) { + return new Prop(propName, rawProps[propName]); + }); + return function () { + var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; + // Holds component state + var state = Object.assign({}, stateInit instanceof Function ? stateInit(options) : stateInit, + // Support plain objects for backwards compatibility + { + initialised: false + }); + + // keeps track of which props triggered an update + var changedProps = {}; + + // Component constructor + function comp(nodeElement) { + initStatic(nodeElement, options); + digest(); + return comp; + } + var initStatic = function initStatic(nodeElement, options) { + initFn.call(comp, nodeElement, state, options); + state.initialised = true; + }; + var digest = debounce(function () { + if (!state.initialised) { + return; + } + updateFn.call(comp, state, changedProps); + changedProps = {}; + }, 1); + + // Getter/setter methods + props.forEach(function (prop) { + comp[prop.name] = getSetProp(prop); + function getSetProp(_ref3) { + var prop = _ref3.name, + _ref3$triggerUpdate = _ref3.triggerUpdate, + redigest = _ref3$triggerUpdate === void 0 ? false : _ref3$triggerUpdate, + _ref3$onChange = _ref3.onChange, + onChange = _ref3$onChange === void 0 ? function (newVal, state) {} : _ref3$onChange, + _ref3$defaultVal = _ref3.defaultVal, + defaultVal = _ref3$defaultVal === void 0 ? null : _ref3$defaultVal; + return function (_) { + var curVal = state[prop]; + if (!arguments.length) { + return curVal; + } // Getter mode + + var val = _ === undefined ? defaultVal : _; // pick default if value passed is undefined + state[prop] = val; + onChange.call(comp, val, state, curVal); + + // track changed props + !changedProps.hasOwnProperty(prop) && (changedProps[prop] = curVal); + if (redigest) { + digest(); + } + return comp; + }; + } + }); + + // Other methods + Object.keys(methods).forEach(function (methodName) { + comp[methodName] = function () { + var _methods$methodName; + for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) { + args[_key] = arguments[_key]; + } + return (_methods$methodName = methods[methodName]).call.apply(_methods$methodName, [comp, state].concat(args)); + }; + }); + + // Link aliases + Object.entries(aliases).forEach(function (_ref4) { + var _ref5 = _slicedToArray$1(_ref4, 2), + alias = _ref5[0], + target = _ref5[1]; + return comp[alias] = comp[target]; + }); + + // Reset all component props to their default value + comp.resetProps = function () { + props.forEach(function (prop) { + comp[prop.name](prop.defaultVal); + }); + return comp; + }; + + // + + comp.resetProps(); // Apply all prop defaults + state._rerender = digest; // Expose digest method + + return comp; + }; + } + + var index$2 = (function (p) { + return typeof p === 'function' ? p // fn + : typeof p === 'string' ? function (obj) { + return obj[p]; + } // property name + : function (obj) { + return p; + }; + }); // constant + + // This file is autogenerated. It's used to publish ESM to npm. + function _typeof(obj) { + "@babel/helpers - typeof"; + + return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (obj) { + return typeof obj; + } : function (obj) { + return obj && "function" == typeof Symbol && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; + }, _typeof(obj); + } + + // https://github.com/bgrins/TinyColor + // Brian Grinstead, MIT License + + var trimLeft = /^\s+/; + var trimRight = /\s+$/; + function tinycolor(color, opts) { + color = color ? color : ""; + opts = opts || {}; + + // If input is already a tinycolor, return itself + if (color instanceof tinycolor) { + return color; + } + // If we are called as a function, call using new instead + if (!(this instanceof tinycolor)) { + return new tinycolor(color, opts); + } + var rgb = inputToRGB(color); + this._originalInput = color, this._r = rgb.r, this._g = rgb.g, this._b = rgb.b, this._a = rgb.a, this._roundA = Math.round(100 * this._a) / 100, this._format = opts.format || rgb.format; + this._gradientType = opts.gradientType; + + // Don't let the range of [0,255] come back in [0,1]. + // Potentially lose a little bit of precision here, but will fix issues where + // .5 gets interpreted as half of the total, instead of half of 1 + // If it was supposed to be 128, this was already taken care of by `inputToRgb` + if (this._r < 1) this._r = Math.round(this._r); + if (this._g < 1) this._g = Math.round(this._g); + if (this._b < 1) this._b = Math.round(this._b); + this._ok = rgb.ok; + } + tinycolor.prototype = { + isDark: function isDark() { + return this.getBrightness() < 128; + }, + isLight: function isLight() { + return !this.isDark(); + }, + isValid: function isValid() { + return this._ok; + }, + getOriginalInput: function getOriginalInput() { + return this._originalInput; + }, + getFormat: function getFormat() { + return this._format; + }, + getAlpha: function getAlpha() { + return this._a; + }, + getBrightness: function getBrightness() { + //http://www.w3.org/TR/AERT#color-contrast + var rgb = this.toRgb(); + return (rgb.r * 299 + rgb.g * 587 + rgb.b * 114) / 1000; + }, + getLuminance: function getLuminance() { + //http://www.w3.org/TR/2008/REC-WCAG20-20081211/#relativeluminancedef + var rgb = this.toRgb(); + var RsRGB, GsRGB, BsRGB, R, G, B; + RsRGB = rgb.r / 255; + GsRGB = rgb.g / 255; + BsRGB = rgb.b / 255; + if (RsRGB <= 0.03928) R = RsRGB / 12.92;else R = Math.pow((RsRGB + 0.055) / 1.055, 2.4); + if (GsRGB <= 0.03928) G = GsRGB / 12.92;else G = Math.pow((GsRGB + 0.055) / 1.055, 2.4); + if (BsRGB <= 0.03928) B = BsRGB / 12.92;else B = Math.pow((BsRGB + 0.055) / 1.055, 2.4); + return 0.2126 * R + 0.7152 * G + 0.0722 * B; + }, + setAlpha: function setAlpha(value) { + this._a = boundAlpha(value); + this._roundA = Math.round(100 * this._a) / 100; + return this; + }, + toHsv: function toHsv() { + var hsv = rgbToHsv(this._r, this._g, this._b); + return { + h: hsv.h * 360, + s: hsv.s, + v: hsv.v, + a: this._a + }; + }, + toHsvString: function toHsvString() { + var hsv = rgbToHsv(this._r, this._g, this._b); + var h = Math.round(hsv.h * 360), + s = Math.round(hsv.s * 100), + v = Math.round(hsv.v * 100); + return this._a == 1 ? "hsv(" + h + ", " + s + "%, " + v + "%)" : "hsva(" + h + ", " + s + "%, " + v + "%, " + this._roundA + ")"; + }, + toHsl: function toHsl() { + var hsl = rgbToHsl(this._r, this._g, this._b); + return { + h: hsl.h * 360, + s: hsl.s, + l: hsl.l, + a: this._a + }; + }, + toHslString: function toHslString() { + var hsl = rgbToHsl(this._r, this._g, this._b); + var h = Math.round(hsl.h * 360), + s = Math.round(hsl.s * 100), + l = Math.round(hsl.l * 100); + return this._a == 1 ? "hsl(" + h + ", " + s + "%, " + l + "%)" : "hsla(" + h + ", " + s + "%, " + l + "%, " + this._roundA + ")"; + }, + toHex: function toHex(allow3Char) { + return rgbToHex(this._r, this._g, this._b, allow3Char); + }, + toHexString: function toHexString(allow3Char) { + return "#" + this.toHex(allow3Char); + }, + toHex8: function toHex8(allow4Char) { + return rgbaToHex(this._r, this._g, this._b, this._a, allow4Char); + }, + toHex8String: function toHex8String(allow4Char) { + return "#" + this.toHex8(allow4Char); + }, + toRgb: function toRgb() { + return { + r: Math.round(this._r), + g: Math.round(this._g), + b: Math.round(this._b), + a: this._a + }; + }, + toRgbString: function toRgbString() { + return this._a == 1 ? "rgb(" + Math.round(this._r) + ", " + Math.round(this._g) + ", " + Math.round(this._b) + ")" : "rgba(" + Math.round(this._r) + ", " + Math.round(this._g) + ", " + Math.round(this._b) + ", " + this._roundA + ")"; + }, + toPercentageRgb: function toPercentageRgb() { + return { + r: Math.round(bound01(this._r, 255) * 100) + "%", + g: Math.round(bound01(this._g, 255) * 100) + "%", + b: Math.round(bound01(this._b, 255) * 100) + "%", + a: this._a + }; + }, + toPercentageRgbString: function toPercentageRgbString() { + return this._a == 1 ? "rgb(" + Math.round(bound01(this._r, 255) * 100) + "%, " + Math.round(bound01(this._g, 255) * 100) + "%, " + Math.round(bound01(this._b, 255) * 100) + "%)" : "rgba(" + Math.round(bound01(this._r, 255) * 100) + "%, " + Math.round(bound01(this._g, 255) * 100) + "%, " + Math.round(bound01(this._b, 255) * 100) + "%, " + this._roundA + ")"; + }, + toName: function toName() { + if (this._a === 0) { + return "transparent"; + } + if (this._a < 1) { + return false; + } + return hexNames[rgbToHex(this._r, this._g, this._b, true)] || false; + }, + toFilter: function toFilter(secondColor) { + var hex8String = "#" + rgbaToArgbHex(this._r, this._g, this._b, this._a); + var secondHex8String = hex8String; + var gradientType = this._gradientType ? "GradientType = 1, " : ""; + if (secondColor) { + var s = tinycolor(secondColor); + secondHex8String = "#" + rgbaToArgbHex(s._r, s._g, s._b, s._a); + } + return "progid:DXImageTransform.Microsoft.gradient(" + gradientType + "startColorstr=" + hex8String + ",endColorstr=" + secondHex8String + ")"; + }, + toString: function toString(format) { + var formatSet = !!format; + format = format || this._format; + var formattedString = false; + var hasAlpha = this._a < 1 && this._a >= 0; + var needsAlphaFormat = !formatSet && hasAlpha && (format === "hex" || format === "hex6" || format === "hex3" || format === "hex4" || format === "hex8" || format === "name"); + if (needsAlphaFormat) { + // Special case for "transparent", all other non-alpha formats + // will return rgba when there is transparency. + if (format === "name" && this._a === 0) { + return this.toName(); + } + return this.toRgbString(); + } + if (format === "rgb") { + formattedString = this.toRgbString(); + } + if (format === "prgb") { + formattedString = this.toPercentageRgbString(); + } + if (format === "hex" || format === "hex6") { + formattedString = this.toHexString(); + } + if (format === "hex3") { + formattedString = this.toHexString(true); + } + if (format === "hex4") { + formattedString = this.toHex8String(true); + } + if (format === "hex8") { + formattedString = this.toHex8String(); + } + if (format === "name") { + formattedString = this.toName(); + } + if (format === "hsl") { + formattedString = this.toHslString(); + } + if (format === "hsv") { + formattedString = this.toHsvString(); + } + return formattedString || this.toHexString(); + }, + clone: function clone() { + return tinycolor(this.toString()); + }, + _applyModification: function _applyModification(fn, args) { + var color = fn.apply(null, [this].concat([].slice.call(args))); + this._r = color._r; + this._g = color._g; + this._b = color._b; + this.setAlpha(color._a); + return this; + }, + lighten: function lighten() { + return this._applyModification(_lighten, arguments); + }, + brighten: function brighten() { + return this._applyModification(_brighten, arguments); + }, + darken: function darken() { + return this._applyModification(_darken, arguments); + }, + desaturate: function desaturate() { + return this._applyModification(_desaturate, arguments); + }, + saturate: function saturate() { + return this._applyModification(_saturate, arguments); + }, + greyscale: function greyscale() { + return this._applyModification(_greyscale, arguments); + }, + spin: function spin() { + return this._applyModification(_spin, arguments); + }, + _applyCombination: function _applyCombination(fn, args) { + return fn.apply(null, [this].concat([].slice.call(args))); + }, + analogous: function analogous() { + return this._applyCombination(_analogous, arguments); + }, + complement: function complement() { + return this._applyCombination(_complement, arguments); + }, + monochromatic: function monochromatic() { + return this._applyCombination(_monochromatic, arguments); + }, + splitcomplement: function splitcomplement() { + return this._applyCombination(_splitcomplement, arguments); + }, + // Disabled until https://github.com/bgrins/TinyColor/issues/254 + // polyad: function (number) { + // return this._applyCombination(polyad, [number]); + // }, + triad: function triad() { + return this._applyCombination(polyad, [3]); + }, + tetrad: function tetrad() { + return this._applyCombination(polyad, [4]); + } + }; + + // If input is an object, force 1 into "1.0" to handle ratios properly + // String input requires "1.0" as input, so 1 will be treated as 1 + tinycolor.fromRatio = function (color, opts) { + if (_typeof(color) == "object") { + var newColor = {}; + for (var i in color) { + if (color.hasOwnProperty(i)) { + if (i === "a") { + newColor[i] = color[i]; + } else { + newColor[i] = convertToPercentage(color[i]); + } + } + } + color = newColor; + } + return tinycolor(color, opts); + }; + + // Given a string or object, convert that input to RGB + // Possible string inputs: + // + // "red" + // "#f00" or "f00" + // "#ff0000" or "ff0000" + // "#ff000000" or "ff000000" + // "rgb 255 0 0" or "rgb (255, 0, 0)" + // "rgb 1.0 0 0" or "rgb (1, 0, 0)" + // "rgba (255, 0, 0, 1)" or "rgba 255, 0, 0, 1" + // "rgba (1.0, 0, 0, 1)" or "rgba 1.0, 0, 0, 1" + // "hsl(0, 100%, 50%)" or "hsl 0 100% 50%" + // "hsla(0, 100%, 50%, 1)" or "hsla 0 100% 50%, 1" + // "hsv(0, 100%, 100%)" or "hsv 0 100% 100%" + // + function inputToRGB(color) { + var rgb = { + r: 0, + g: 0, + b: 0 + }; + var a = 1; + var s = null; + var v = null; + var l = null; + var ok = false; + var format = false; + if (typeof color == "string") { + color = stringInputToObject(color); + } + if (_typeof(color) == "object") { + if (isValidCSSUnit(color.r) && isValidCSSUnit(color.g) && isValidCSSUnit(color.b)) { + rgb = rgbToRgb(color.r, color.g, color.b); + ok = true; + format = String(color.r).substr(-1) === "%" ? "prgb" : "rgb"; + } else if (isValidCSSUnit(color.h) && isValidCSSUnit(color.s) && isValidCSSUnit(color.v)) { + s = convertToPercentage(color.s); + v = convertToPercentage(color.v); + rgb = hsvToRgb(color.h, s, v); + ok = true; + format = "hsv"; + } else if (isValidCSSUnit(color.h) && isValidCSSUnit(color.s) && isValidCSSUnit(color.l)) { + s = convertToPercentage(color.s); + l = convertToPercentage(color.l); + rgb = hslToRgb(color.h, s, l); + ok = true; + format = "hsl"; + } + if (color.hasOwnProperty("a")) { + a = color.a; + } + } + a = boundAlpha(a); + return { + ok: ok, + format: color.format || format, + r: Math.min(255, Math.max(rgb.r, 0)), + g: Math.min(255, Math.max(rgb.g, 0)), + b: Math.min(255, Math.max(rgb.b, 0)), + a: a + }; + } + + // Conversion Functions + // -------------------- + + // `rgbToHsl`, `rgbToHsv`, `hslToRgb`, `hsvToRgb` modified from: + // + + // `rgbToRgb` + // Handle bounds / percentage checking to conform to CSS color spec + // + // *Assumes:* r, g, b in [0, 255] or [0, 1] + // *Returns:* { r, g, b } in [0, 255] + function rgbToRgb(r, g, b) { + return { + r: bound01(r, 255) * 255, + g: bound01(g, 255) * 255, + b: bound01(b, 255) * 255 + }; + } + + // `rgbToHsl` + // Converts an RGB color value to HSL. + // *Assumes:* r, g, and b are contained in [0, 255] or [0, 1] + // *Returns:* { h, s, l } in [0,1] + function rgbToHsl(r, g, b) { + r = bound01(r, 255); + g = bound01(g, 255); + b = bound01(b, 255); + var max = Math.max(r, g, b), + min = Math.min(r, g, b); + var h, + s, + l = (max + min) / 2; + if (max == min) { + h = s = 0; // achromatic + } else { + var d = max - min; + s = l > 0.5 ? d / (2 - max - min) : d / (max + min); + switch (max) { + case r: + h = (g - b) / d + (g < b ? 6 : 0); + break; + case g: + h = (b - r) / d + 2; + break; + case b: + h = (r - g) / d + 4; + break; + } + h /= 6; + } + return { + h: h, + s: s, + l: l + }; + } + + // `hslToRgb` + // Converts an HSL color value to RGB. + // *Assumes:* h is contained in [0, 1] or [0, 360] and s and l are contained [0, 1] or [0, 100] + // *Returns:* { r, g, b } in the set [0, 255] + function hslToRgb(h, s, l) { + var r, g, b; + h = bound01(h, 360); + s = bound01(s, 100); + l = bound01(l, 100); + function hue2rgb(p, q, t) { + if (t < 0) t += 1; + if (t > 1) t -= 1; + if (t < 1 / 6) return p + (q - p) * 6 * t; + if (t < 1 / 2) return q; + if (t < 2 / 3) return p + (q - p) * (2 / 3 - t) * 6; + return p; + } + if (s === 0) { + r = g = b = l; // achromatic + } else { + var q = l < 0.5 ? l * (1 + s) : l + s - l * s; + var p = 2 * l - q; + r = hue2rgb(p, q, h + 1 / 3); + g = hue2rgb(p, q, h); + b = hue2rgb(p, q, h - 1 / 3); + } + return { + r: r * 255, + g: g * 255, + b: b * 255 + }; + } + + // `rgbToHsv` + // Converts an RGB color value to HSV + // *Assumes:* r, g, and b are contained in the set [0, 255] or [0, 1] + // *Returns:* { h, s, v } in [0,1] + function rgbToHsv(r, g, b) { + r = bound01(r, 255); + g = bound01(g, 255); + b = bound01(b, 255); + var max = Math.max(r, g, b), + min = Math.min(r, g, b); + var h, + s, + v = max; + var d = max - min; + s = max === 0 ? 0 : d / max; + if (max == min) { + h = 0; // achromatic + } else { + switch (max) { + case r: + h = (g - b) / d + (g < b ? 6 : 0); + break; + case g: + h = (b - r) / d + 2; + break; + case b: + h = (r - g) / d + 4; + break; + } + h /= 6; + } + return { + h: h, + s: s, + v: v + }; + } + + // `hsvToRgb` + // Converts an HSV color value to RGB. + // *Assumes:* h is contained in [0, 1] or [0, 360] and s and v are contained in [0, 1] or [0, 100] + // *Returns:* { r, g, b } in the set [0, 255] + function hsvToRgb(h, s, v) { + h = bound01(h, 360) * 6; + s = bound01(s, 100); + v = bound01(v, 100); + var i = Math.floor(h), + f = h - i, + p = v * (1 - s), + q = v * (1 - f * s), + t = v * (1 - (1 - f) * s), + mod = i % 6, + r = [v, q, p, p, t, v][mod], + g = [t, v, v, q, p, p][mod], + b = [p, p, t, v, v, q][mod]; + return { + r: r * 255, + g: g * 255, + b: b * 255 + }; + } + + // `rgbToHex` + // Converts an RGB color to hex + // Assumes r, g, and b are contained in the set [0, 255] + // Returns a 3 or 6 character hex + function rgbToHex(r, g, b, allow3Char) { + var hex = [pad2(Math.round(r).toString(16)), pad2(Math.round(g).toString(16)), pad2(Math.round(b).toString(16))]; + + // Return a 3 character hex if possible + if (allow3Char && hex[0].charAt(0) == hex[0].charAt(1) && hex[1].charAt(0) == hex[1].charAt(1) && hex[2].charAt(0) == hex[2].charAt(1)) { + return hex[0].charAt(0) + hex[1].charAt(0) + hex[2].charAt(0); + } + return hex.join(""); + } + + // `rgbaToHex` + // Converts an RGBA color plus alpha transparency to hex + // Assumes r, g, b are contained in the set [0, 255] and + // a in [0, 1]. Returns a 4 or 8 character rgba hex + function rgbaToHex(r, g, b, a, allow4Char) { + var hex = [pad2(Math.round(r).toString(16)), pad2(Math.round(g).toString(16)), pad2(Math.round(b).toString(16)), pad2(convertDecimalToHex(a))]; + + // Return a 4 character hex if possible + if (allow4Char && hex[0].charAt(0) == hex[0].charAt(1) && hex[1].charAt(0) == hex[1].charAt(1) && hex[2].charAt(0) == hex[2].charAt(1) && hex[3].charAt(0) == hex[3].charAt(1)) { + return hex[0].charAt(0) + hex[1].charAt(0) + hex[2].charAt(0) + hex[3].charAt(0); + } + return hex.join(""); + } + + // `rgbaToArgbHex` + // Converts an RGBA color to an ARGB Hex8 string + // Rarely used, but required for "toFilter()" + function rgbaToArgbHex(r, g, b, a) { + var hex = [pad2(convertDecimalToHex(a)), pad2(Math.round(r).toString(16)), pad2(Math.round(g).toString(16)), pad2(Math.round(b).toString(16))]; + return hex.join(""); + } + + // `equals` + // Can be called with any tinycolor input + tinycolor.equals = function (color1, color2) { + if (!color1 || !color2) return false; + return tinycolor(color1).toRgbString() == tinycolor(color2).toRgbString(); + }; + tinycolor.random = function () { + return tinycolor.fromRatio({ + r: Math.random(), + g: Math.random(), + b: Math.random() + }); + }; + + // Modification Functions + // ---------------------- + // Thanks to less.js for some of the basics here + // + + function _desaturate(color, amount) { + amount = amount === 0 ? 0 : amount || 10; + var hsl = tinycolor(color).toHsl(); + hsl.s -= amount / 100; + hsl.s = clamp01(hsl.s); + return tinycolor(hsl); + } + function _saturate(color, amount) { + amount = amount === 0 ? 0 : amount || 10; + var hsl = tinycolor(color).toHsl(); + hsl.s += amount / 100; + hsl.s = clamp01(hsl.s); + return tinycolor(hsl); + } + function _greyscale(color) { + return tinycolor(color).desaturate(100); + } + function _lighten(color, amount) { + amount = amount === 0 ? 0 : amount || 10; + var hsl = tinycolor(color).toHsl(); + hsl.l += amount / 100; + hsl.l = clamp01(hsl.l); + return tinycolor(hsl); + } + function _brighten(color, amount) { + amount = amount === 0 ? 0 : amount || 10; + var rgb = tinycolor(color).toRgb(); + rgb.r = Math.max(0, Math.min(255, rgb.r - Math.round(255 * -(amount / 100)))); + rgb.g = Math.max(0, Math.min(255, rgb.g - Math.round(255 * -(amount / 100)))); + rgb.b = Math.max(0, Math.min(255, rgb.b - Math.round(255 * -(amount / 100)))); + return tinycolor(rgb); + } + function _darken(color, amount) { + amount = amount === 0 ? 0 : amount || 10; + var hsl = tinycolor(color).toHsl(); + hsl.l -= amount / 100; + hsl.l = clamp01(hsl.l); + return tinycolor(hsl); + } + + // Spin takes a positive or negative amount within [-360, 360] indicating the change of hue. + // Values outside of this range will be wrapped into this range. + function _spin(color, amount) { + var hsl = tinycolor(color).toHsl(); + var hue = (hsl.h + amount) % 360; + hsl.h = hue < 0 ? 360 + hue : hue; + return tinycolor(hsl); + } + + // Combination Functions + // --------------------- + // Thanks to jQuery xColor for some of the ideas behind these + // + + function _complement(color) { + var hsl = tinycolor(color).toHsl(); + hsl.h = (hsl.h + 180) % 360; + return tinycolor(hsl); + } + function polyad(color, number) { + if (isNaN(number) || number <= 0) { + throw new Error("Argument to polyad must be a positive number"); + } + var hsl = tinycolor(color).toHsl(); + var result = [tinycolor(color)]; + var step = 360 / number; + for (var i = 1; i < number; i++) { + result.push(tinycolor({ + h: (hsl.h + i * step) % 360, + s: hsl.s, + l: hsl.l + })); + } + return result; + } + function _splitcomplement(color) { + var hsl = tinycolor(color).toHsl(); + var h = hsl.h; + return [tinycolor(color), tinycolor({ + h: (h + 72) % 360, + s: hsl.s, + l: hsl.l + }), tinycolor({ + h: (h + 216) % 360, + s: hsl.s, + l: hsl.l + })]; + } + function _analogous(color, results, slices) { + results = results || 6; + slices = slices || 30; + var hsl = tinycolor(color).toHsl(); + var part = 360 / slices; + var ret = [tinycolor(color)]; + for (hsl.h = (hsl.h - (part * results >> 1) + 720) % 360; --results;) { + hsl.h = (hsl.h + part) % 360; + ret.push(tinycolor(hsl)); + } + return ret; + } + function _monochromatic(color, results) { + results = results || 6; + var hsv = tinycolor(color).toHsv(); + var h = hsv.h, + s = hsv.s, + v = hsv.v; + var ret = []; + var modification = 1 / results; + while (results--) { + ret.push(tinycolor({ + h: h, + s: s, + v: v + })); + v = (v + modification) % 1; + } + return ret; + } + + // Utility Functions + // --------------------- + + tinycolor.mix = function (color1, color2, amount) { + amount = amount === 0 ? 0 : amount || 50; + var rgb1 = tinycolor(color1).toRgb(); + var rgb2 = tinycolor(color2).toRgb(); + var p = amount / 100; + var rgba = { + r: (rgb2.r - rgb1.r) * p + rgb1.r, + g: (rgb2.g - rgb1.g) * p + rgb1.g, + b: (rgb2.b - rgb1.b) * p + rgb1.b, + a: (rgb2.a - rgb1.a) * p + rgb1.a + }; + return tinycolor(rgba); + }; + + // Readability Functions + // --------------------- + // false + // tinycolor.isReadable("#000", "#111",{level:"AA",size:"large"}) => false + tinycolor.isReadable = function (color1, color2, wcag2) { + var readability = tinycolor.readability(color1, color2); + var wcag2Parms, out; + out = false; + wcag2Parms = validateWCAG2Parms(wcag2); + switch (wcag2Parms.level + wcag2Parms.size) { + case "AAsmall": + case "AAAlarge": + out = readability >= 4.5; + break; + case "AAlarge": + out = readability >= 3; + break; + case "AAAsmall": + out = readability >= 7; + break; + } + return out; + }; + + // `mostReadable` + // Given a base color and a list of possible foreground or background + // colors for that base, returns the most readable color. + // Optionally returns Black or White if the most readable color is unreadable. + // *Example* + // tinycolor.mostReadable(tinycolor.mostReadable("#123", ["#124", "#125"],{includeFallbackColors:false}).toHexString(); // "#112255" + // tinycolor.mostReadable(tinycolor.mostReadable("#123", ["#124", "#125"],{includeFallbackColors:true}).toHexString(); // "#ffffff" + // tinycolor.mostReadable("#a8015a", ["#faf3f3"],{includeFallbackColors:true,level:"AAA",size:"large"}).toHexString(); // "#faf3f3" + // tinycolor.mostReadable("#a8015a", ["#faf3f3"],{includeFallbackColors:true,level:"AAA",size:"small"}).toHexString(); // "#ffffff" + tinycolor.mostReadable = function (baseColor, colorList, args) { + var bestColor = null; + var bestScore = 0; + var readability; + var includeFallbackColors, level, size; + args = args || {}; + includeFallbackColors = args.includeFallbackColors; + level = args.level; + size = args.size; + for (var i = 0; i < colorList.length; i++) { + readability = tinycolor.readability(baseColor, colorList[i]); + if (readability > bestScore) { + bestScore = readability; + bestColor = tinycolor(colorList[i]); + } + } + if (tinycolor.isReadable(baseColor, bestColor, { + level: level, + size: size + }) || !includeFallbackColors) { + return bestColor; + } else { + args.includeFallbackColors = false; + return tinycolor.mostReadable(baseColor, ["#fff", "#000"], args); + } + }; + + // Big List of Colors + // ------------------ + // + var names = tinycolor.names = { + aliceblue: "f0f8ff", + antiquewhite: "faebd7", + aqua: "0ff", + aquamarine: "7fffd4", + azure: "f0ffff", + beige: "f5f5dc", + bisque: "ffe4c4", + black: "000", + blanchedalmond: "ffebcd", + blue: "00f", + blueviolet: "8a2be2", + brown: "a52a2a", + burlywood: "deb887", + burntsienna: "ea7e5d", + cadetblue: "5f9ea0", + chartreuse: "7fff00", + chocolate: "d2691e", + coral: "ff7f50", + cornflowerblue: "6495ed", + cornsilk: "fff8dc", + crimson: "dc143c", + cyan: "0ff", + darkblue: "00008b", + darkcyan: "008b8b", + darkgoldenrod: "b8860b", + darkgray: "a9a9a9", + darkgreen: "006400", + darkgrey: "a9a9a9", + darkkhaki: "bdb76b", + darkmagenta: "8b008b", + darkolivegreen: "556b2f", + darkorange: "ff8c00", + darkorchid: "9932cc", + darkred: "8b0000", + darksalmon: "e9967a", + darkseagreen: "8fbc8f", + darkslateblue: "483d8b", + darkslategray: "2f4f4f", + darkslategrey: "2f4f4f", + darkturquoise: "00ced1", + darkviolet: "9400d3", + deeppink: "ff1493", + deepskyblue: "00bfff", + dimgray: "696969", + dimgrey: "696969", + dodgerblue: "1e90ff", + firebrick: "b22222", + floralwhite: "fffaf0", + forestgreen: "228b22", + fuchsia: "f0f", + gainsboro: "dcdcdc", + ghostwhite: "f8f8ff", + gold: "ffd700", + goldenrod: "daa520", + gray: "808080", + green: "008000", + greenyellow: "adff2f", + grey: "808080", + honeydew: "f0fff0", + hotpink: "ff69b4", + indianred: "cd5c5c", + indigo: "4b0082", + ivory: "fffff0", + khaki: "f0e68c", + lavender: "e6e6fa", + lavenderblush: "fff0f5", + lawngreen: "7cfc00", + lemonchiffon: "fffacd", + lightblue: "add8e6", + lightcoral: "f08080", + lightcyan: "e0ffff", + lightgoldenrodyellow: "fafad2", + lightgray: "d3d3d3", + lightgreen: "90ee90", + lightgrey: "d3d3d3", + lightpink: "ffb6c1", + lightsalmon: "ffa07a", + lightseagreen: "20b2aa", + lightskyblue: "87cefa", + lightslategray: "789", + lightslategrey: "789", + lightsteelblue: "b0c4de", + lightyellow: "ffffe0", + lime: "0f0", + limegreen: "32cd32", + linen: "faf0e6", + magenta: "f0f", + maroon: "800000", + mediumaquamarine: "66cdaa", + mediumblue: "0000cd", + mediumorchid: "ba55d3", + mediumpurple: "9370db", + mediumseagreen: "3cb371", + mediumslateblue: "7b68ee", + mediumspringgreen: "00fa9a", + mediumturquoise: "48d1cc", + mediumvioletred: "c71585", + midnightblue: "191970", + mintcream: "f5fffa", + mistyrose: "ffe4e1", + moccasin: "ffe4b5", + navajowhite: "ffdead", + navy: "000080", + oldlace: "fdf5e6", + olive: "808000", + olivedrab: "6b8e23", + orange: "ffa500", + orangered: "ff4500", + orchid: "da70d6", + palegoldenrod: "eee8aa", + palegreen: "98fb98", + paleturquoise: "afeeee", + palevioletred: "db7093", + papayawhip: "ffefd5", + peachpuff: "ffdab9", + peru: "cd853f", + pink: "ffc0cb", + plum: "dda0dd", + powderblue: "b0e0e6", + purple: "800080", + rebeccapurple: "663399", + red: "f00", + rosybrown: "bc8f8f", + royalblue: "4169e1", + saddlebrown: "8b4513", + salmon: "fa8072", + sandybrown: "f4a460", + seagreen: "2e8b57", + seashell: "fff5ee", + sienna: "a0522d", + silver: "c0c0c0", + skyblue: "87ceeb", + slateblue: "6a5acd", + slategray: "708090", + slategrey: "708090", + snow: "fffafa", + springgreen: "00ff7f", + steelblue: "4682b4", + tan: "d2b48c", + teal: "008080", + thistle: "d8bfd8", + tomato: "ff6347", + turquoise: "40e0d0", + violet: "ee82ee", + wheat: "f5deb3", + white: "fff", + whitesmoke: "f5f5f5", + yellow: "ff0", + yellowgreen: "9acd32" + }; + + // Make it easy to access colors via `hexNames[hex]` + var hexNames = tinycolor.hexNames = flip(names); + + // Utilities + // --------- + + // `{ 'name1': 'val1' }` becomes `{ 'val1': 'name1' }` + function flip(o) { + var flipped = {}; + for (var i in o) { + if (o.hasOwnProperty(i)) { + flipped[o[i]] = i; + } + } + return flipped; + } + + // Return a valid alpha value [0,1] with all invalid values being set to 1 + function boundAlpha(a) { + a = parseFloat(a); + if (isNaN(a) || a < 0 || a > 1) { + a = 1; + } + return a; + } + + // Take input from [0, n] and return it as [0, 1] + function bound01(n, max) { + if (isOnePointZero(n)) n = "100%"; + var processPercent = isPercentage(n); + n = Math.min(max, Math.max(0, parseFloat(n))); + + // Automatically convert percentage into number + if (processPercent) { + n = parseInt(n * max, 10) / 100; + } + + // Handle floating point rounding errors + if (Math.abs(n - max) < 0.000001) { + return 1; + } + + // Convert into [0, 1] range if it isn't already + return n % max / parseFloat(max); + } + + // Force a number between 0 and 1 + function clamp01(val) { + return Math.min(1, Math.max(0, val)); + } + + // Parse a base-16 hex value into a base-10 integer + function parseIntFromHex(val) { + return parseInt(val, 16); + } + + // Need to handle 1.0 as 100%, since once it is a number, there is no difference between it and 1 + // + function isOnePointZero(n) { + return typeof n == "string" && n.indexOf(".") != -1 && parseFloat(n) === 1; + } + + // Check to see if string passed in is a percentage + function isPercentage(n) { + return typeof n === "string" && n.indexOf("%") != -1; + } + + // Force a hex value to have 2 characters + function pad2(c) { + return c.length == 1 ? "0" + c : "" + c; + } + + // Replace a decimal with it's percentage value + function convertToPercentage(n) { + if (n <= 1) { + n = n * 100 + "%"; + } + return n; + } + + // Converts a decimal to a hex value + function convertDecimalToHex(d) { + return Math.round(parseFloat(d) * 255).toString(16); + } + // Converts a hex value to a decimal + function convertHexToDecimal(h) { + return parseIntFromHex(h) / 255; + } + var matchers = function () { + // + var CSS_INTEGER = "[-\\+]?\\d+%?"; + + // + var CSS_NUMBER = "[-\\+]?\\d*\\.\\d+%?"; + + // Allow positive/negative integer/number. Don't capture the either/or, just the entire outcome. + var CSS_UNIT = "(?:" + CSS_NUMBER + ")|(?:" + CSS_INTEGER + ")"; + + // Actual matching. + // Parentheses and commas are optional, but not required. + // Whitespace can take the place of commas or opening paren + var PERMISSIVE_MATCH3 = "[\\s|\\(]+(" + CSS_UNIT + ")[,|\\s]+(" + CSS_UNIT + ")[,|\\s]+(" + CSS_UNIT + ")\\s*\\)?"; + var PERMISSIVE_MATCH4 = "[\\s|\\(]+(" + CSS_UNIT + ")[,|\\s]+(" + CSS_UNIT + ")[,|\\s]+(" + CSS_UNIT + ")[,|\\s]+(" + CSS_UNIT + ")\\s*\\)?"; + return { + CSS_UNIT: new RegExp(CSS_UNIT), + rgb: new RegExp("rgb" + PERMISSIVE_MATCH3), + rgba: new RegExp("rgba" + PERMISSIVE_MATCH4), + hsl: new RegExp("hsl" + PERMISSIVE_MATCH3), + hsla: new RegExp("hsla" + PERMISSIVE_MATCH4), + hsv: new RegExp("hsv" + PERMISSIVE_MATCH3), + hsva: new RegExp("hsva" + PERMISSIVE_MATCH4), + hex3: /^#?([0-9a-fA-F]{1})([0-9a-fA-F]{1})([0-9a-fA-F]{1})$/, + hex6: /^#?([0-9a-fA-F]{2})([0-9a-fA-F]{2})([0-9a-fA-F]{2})$/, + hex4: /^#?([0-9a-fA-F]{1})([0-9a-fA-F]{1})([0-9a-fA-F]{1})([0-9a-fA-F]{1})$/, + hex8: /^#?([0-9a-fA-F]{2})([0-9a-fA-F]{2})([0-9a-fA-F]{2})([0-9a-fA-F]{2})$/ + }; + }(); + + // `isValidCSSUnit` + // Take in a single string / number and check to see if it looks like a CSS unit + // (see `matchers` above for definition). + function isValidCSSUnit(color) { + return !!matchers.CSS_UNIT.exec(color); + } + + // `stringInputToObject` + // Permissive string parsing. Take in a number of formats, and output an object + // based on detected format. Returns `{ r, g, b }` or `{ h, s, l }` or `{ h, s, v}` + function stringInputToObject(color) { + color = color.replace(trimLeft, "").replace(trimRight, "").toLowerCase(); + var named = false; + if (names[color]) { + color = names[color]; + named = true; + } else if (color == "transparent") { + return { + r: 0, + g: 0, + b: 0, + a: 0, + format: "name" + }; + } + + // Try to match string input using regular expressions. + // Keep most of the number bounding out of this function - don't worry about [0,1] or [0,100] or [0,360] + // Just return an object and let the conversion functions handle that. + // This way the result will be the same whether the tinycolor is initialized with string or object. + var match; + if (match = matchers.rgb.exec(color)) { + return { + r: match[1], + g: match[2], + b: match[3] + }; + } + if (match = matchers.rgba.exec(color)) { + return { + r: match[1], + g: match[2], + b: match[3], + a: match[4] + }; + } + if (match = matchers.hsl.exec(color)) { + return { + h: match[1], + s: match[2], + l: match[3] + }; + } + if (match = matchers.hsla.exec(color)) { + return { + h: match[1], + s: match[2], + l: match[3], + a: match[4] + }; + } + if (match = matchers.hsv.exec(color)) { + return { + h: match[1], + s: match[2], + v: match[3] + }; + } + if (match = matchers.hsva.exec(color)) { + return { + h: match[1], + s: match[2], + v: match[3], + a: match[4] + }; + } + if (match = matchers.hex8.exec(color)) { + return { + r: parseIntFromHex(match[1]), + g: parseIntFromHex(match[2]), + b: parseIntFromHex(match[3]), + a: convertHexToDecimal(match[4]), + format: named ? "name" : "hex8" + }; + } + if (match = matchers.hex6.exec(color)) { + return { + r: parseIntFromHex(match[1]), + g: parseIntFromHex(match[2]), + b: parseIntFromHex(match[3]), + format: named ? "name" : "hex" + }; + } + if (match = matchers.hex4.exec(color)) { + return { + r: parseIntFromHex(match[1] + "" + match[1]), + g: parseIntFromHex(match[2] + "" + match[2]), + b: parseIntFromHex(match[3] + "" + match[3]), + a: convertHexToDecimal(match[4] + "" + match[4]), + format: named ? "name" : "hex8" + }; + } + if (match = matchers.hex3.exec(color)) { + return { + r: parseIntFromHex(match[1] + "" + match[1]), + g: parseIntFromHex(match[2] + "" + match[2]), + b: parseIntFromHex(match[3] + "" + match[3]), + format: named ? "name" : "hex" + }; + } + return false; + } + function validateWCAG2Parms(parms) { + // return valid WCAG2 parms for isReadable. + // If input parms are invalid, return {"level":"AA", "size":"small"} + var level, size; + parms = parms || { + level: "AA", + size: "small" + }; + level = (parms.level || "AA").toUpperCase(); + size = (parms.size || "small").toLowerCase(); + if (level !== "AA" && level !== "AAA") { + level = "AA"; + } + if (size !== "small" && size !== "large") { + size = "small"; + } + return { + level: level, + size: size + }; + } + + function _classCallCheck(instance, Constructor) { + if (!(instance instanceof Constructor)) { + throw new TypeError("Cannot call a class as a function"); + } + } + function _defineProperties(target, props) { + for (var i = 0; i < props.length; i++) { + var descriptor = props[i]; + descriptor.enumerable = descriptor.enumerable || false; + descriptor.configurable = true; + if ("value" in descriptor) descriptor.writable = true; + Object.defineProperty(target, _toPropertyKey$1(descriptor.key), descriptor); + } + } + function _createClass(Constructor, protoProps, staticProps) { + if (protoProps) _defineProperties(Constructor.prototype, protoProps); + if (staticProps) _defineProperties(Constructor, staticProps); + Object.defineProperty(Constructor, "prototype", { + writable: false + }); + return Constructor; + } + function _toConsumableArray$1(arr) { + return _arrayWithoutHoles$1(arr) || _iterableToArray$1(arr) || _unsupportedIterableToArray$1(arr) || _nonIterableSpread$1(); + } + function _arrayWithoutHoles$1(arr) { + if (Array.isArray(arr)) return _arrayLikeToArray$1(arr); + } + function _iterableToArray$1(iter) { + if (typeof Symbol !== "undefined" && iter[Symbol.iterator] != null || iter["@@iterator"] != null) return Array.from(iter); + } + function _unsupportedIterableToArray$1(o, minLen) { + if (!o) return; + if (typeof o === "string") return _arrayLikeToArray$1(o, minLen); + var n = Object.prototype.toString.call(o).slice(8, -1); + if (n === "Object" && o.constructor) n = o.constructor.name; + if (n === "Map" || n === "Set") return Array.from(o); + if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray$1(o, minLen); + } + function _arrayLikeToArray$1(arr, len) { + if (len == null || len > arr.length) len = arr.length; + for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i]; + return arr2; + } + function _nonIterableSpread$1() { + throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); + } + function _toPrimitive$1(input, hint) { + if (typeof input !== "object" || input === null) return input; + var prim = input[Symbol.toPrimitive]; + if (prim !== undefined) { + var res = prim.call(input, hint || "default"); + if (typeof res !== "object") return res; + throw new TypeError("@@toPrimitive must return a primitive value."); + } + return (hint === "string" ? String : Number)(input); + } + function _toPropertyKey$1(arg) { + var key = _toPrimitive$1(arg, "string"); + return typeof key === "symbol" ? key : String(key); + } + + var ENTROPY = 123; // Raise numbers to prevent collisions in lower indexes + + var int2HexColor = function int2HexColor(num) { + return "#".concat(Math.min(num, Math.pow(2, 24)).toString(16).padStart(6, '0')); + }; + var rgb2Int = function rgb2Int(r, g, b) { + return (r << 16) + (g << 8) + b; + }; + var colorStr2Int = function colorStr2Int(str) { + var _tinyColor$toRgb = tinycolor(str).toRgb(), + r = _tinyColor$toRgb.r, + g = _tinyColor$toRgb.g, + b = _tinyColor$toRgb.b; + return rgb2Int(r, g, b); + }; + var checksum = function checksum(n, csBits) { + return n * ENTROPY % Math.pow(2, csBits); + }; + var _default = /*#__PURE__*/function () { + function _default() { + var csBits = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 6; + _classCallCheck(this, _default); + this.csBits = csBits; // How many bits to reserve for checksum. Will eat away into the usable size of the registry. + this.registry = ['__reserved for background__']; // indexed objects for rgb lookup; + } + _createClass(_default, [{ + key: "register", + value: function register(obj) { + if (this.registry.length >= Math.pow(2, 24 - this.csBits)) { + // color has 24 bits (-checksum) + return null; // Registry is full + } + + var idx = this.registry.length; + var cs = checksum(idx, this.csBits); + var color = int2HexColor(idx + (cs << 24 - this.csBits)); + this.registry.push(obj); + return color; + } + }, { + key: "lookup", + value: function lookup(color) { + var n = typeof color === 'string' ? colorStr2Int(color) : rgb2Int.apply(void 0, _toConsumableArray$1(color)); + if (!n) return null; // 0 index is reserved for background + + var idx = n & Math.pow(2, 24 - this.csBits) - 1; // registry index + var cs = n >> 24 - this.csBits & Math.pow(2, this.csBits) - 1; // extract bits reserved for checksum + + if (checksum(idx, this.csBits) !== cs || idx >= this.registry.length) return null; // failed checksum or registry out of bounds + + return this.registry[idx]; + } + }]); + return _default; + }(); + + function d3ForceCenter(x, y, z) { + var nodes, strength = 1; + + if (x == null) x = 0; + if (y == null) y = 0; + if (z == null) z = 0; + + function force() { + var i, + n = nodes.length, + node, + sx = 0, + sy = 0, + sz = 0; + + for (i = 0; i < n; ++i) { + node = nodes[i], sx += node.x || 0, sy += node.y || 0, sz += node.z || 0; + } + + for (sx = (sx / n - x) * strength, sy = (sy / n - y) * strength, sz = (sz / n - z) * strength, i = 0; i < n; ++i) { + node = nodes[i]; + if (sx) { node.x -= sx; } + if (sy) { node.y -= sy; } + if (sz) { node.z -= sz; } + } + } + + force.initialize = function(_) { + nodes = _; + }; + + force.x = function(_) { + return arguments.length ? (x = +_, force) : x; + }; + + force.y = function(_) { + return arguments.length ? (y = +_, force) : y; + }; + + force.z = function(_) { + return arguments.length ? (z = +_, force) : z; + }; + + force.strength = function(_) { + return arguments.length ? (strength = +_, force) : strength; + }; + + return force; + } + + function tree_add$2(d) { + const x = +this._x.call(null, d); + return add$2(this.cover(x), x, d); + } + + function add$2(tree, x, d) { + if (isNaN(x)) return tree; // ignore invalid points + + var parent, + node = tree._root, + leaf = {data: d}, + x0 = tree._x0, + x1 = tree._x1, + xm, + xp, + right, + i, + j; + + // If the tree is empty, initialize the root as a leaf. + if (!node) return tree._root = leaf, tree; + + // Find the existing leaf for the new point, or add it. + while (node.length) { + if (right = x >= (xm = (x0 + x1) / 2)) x0 = xm; else x1 = xm; + if (parent = node, !(node = node[i = +right])) return parent[i] = leaf, tree; + } + + // Is the new point is exactly coincident with the existing point? + xp = +tree._x.call(null, node.data); + if (x === xp) return leaf.next = node, parent ? parent[i] = leaf : tree._root = leaf, tree; + + // Otherwise, split the leaf node until the old and new point are separated. + do { + parent = parent ? parent[i] = new Array(2) : tree._root = new Array(2); + if (right = x >= (xm = (x0 + x1) / 2)) x0 = xm; else x1 = xm; + } while ((i = +right) === (j = +(xp >= xm))); + return parent[j] = node, parent[i] = leaf, tree; + } + + function addAll$2(data) { + if (!Array.isArray(data)) data = Array.from(data); + const n = data.length; + const xz = new Float64Array(n); + let x0 = Infinity, + x1 = -Infinity; + + // Compute the points and their extent. + for (let i = 0, x; i < n; ++i) { + if (isNaN(x = +this._x.call(null, data[i]))) continue; + xz[i] = x; + if (x < x0) x0 = x; + if (x > x1) x1 = x; + } + + // If there were no (valid) points, abort. + if (x0 > x1) return this; + + // Expand the tree to cover the new points. + this.cover(x0).cover(x1); + + // Add the new points. + for (let i = 0; i < n; ++i) { + add$2(this, xz[i], data[i]); + } + + return this; + } + + function tree_cover$2(x) { + if (isNaN(x = +x)) return this; // ignore invalid points + + var x0 = this._x0, + x1 = this._x1; + + // If the binarytree has no extent, initialize them. + // Integer extent are necessary so that if we later double the extent, + // the existing half boundaries don’t change due to floating point error! + if (isNaN(x0)) { + x1 = (x0 = Math.floor(x)) + 1; + } + + // Otherwise, double repeatedly to cover. + else { + var z = x1 - x0 || 1, + node = this._root, + parent, + i; + + while (x0 > x || x >= x1) { + i = +(x < x0); + parent = new Array(2), parent[i] = node, node = parent, z *= 2; + switch (i) { + case 0: x1 = x0 + z; break; + case 1: x0 = x1 - z; break; + } + } + + if (this._root && this._root.length) this._root = node; + } + + this._x0 = x0; + this._x1 = x1; + return this; + } + + function tree_data$2() { + var data = []; + this.visit(function(node) { + if (!node.length) do data.push(node.data); while (node = node.next) + }); + return data; + } + + function tree_extent$2(_) { + return arguments.length + ? this.cover(+_[0][0]).cover(+_[1][0]) + : isNaN(this._x0) ? undefined : [[this._x0], [this._x1]]; + } + + function Half(node, x0, x1) { + this.node = node; + this.x0 = x0; + this.x1 = x1; + } + + function tree_find$2(x, radius) { + var data, + x0 = this._x0, + x1, + x2, + x3 = this._x1, + halves = [], + node = this._root, + q, + i; + + if (node) halves.push(new Half(node, x0, x3)); + if (radius == null) radius = Infinity; + else { + x0 = x - radius; + x3 = x + radius; + } + + while (q = halves.pop()) { + + // Stop searching if this half can’t contain a closer node. + if (!(node = q.node) + || (x1 = q.x0) > x3 + || (x2 = q.x1) < x0) continue; + + // Bisect the current half. + if (node.length) { + var xm = (x1 + x2) / 2; + + halves.push( + new Half(node[1], xm, x2), + new Half(node[0], x1, xm) + ); + + // Visit the closest half first. + if (i = +(x >= xm)) { + q = halves[halves.length - 1]; + halves[halves.length - 1] = halves[halves.length - 1 - i]; + halves[halves.length - 1 - i] = q; + } + } + + // Visit this point. (Visiting coincident points isn’t necessary!) + else { + var d = Math.abs(x - +this._x.call(null, node.data)); + if (d < radius) { + radius = d; + x0 = x - d; + x3 = x + d; + data = node.data; + } + } + } + + return data; + } + + function tree_remove$2(d) { + if (isNaN(x = +this._x.call(null, d))) return this; // ignore invalid points + + var parent, + node = this._root, + retainer, + previous, + next, + x0 = this._x0, + x1 = this._x1, + x, + xm, + right, + i, + j; + + // If the tree is empty, initialize the root as a leaf. + if (!node) return this; + + // Find the leaf node for the point. + // While descending, also retain the deepest parent with a non-removed sibling. + if (node.length) while (true) { + if (right = x >= (xm = (x0 + x1) / 2)) x0 = xm; else x1 = xm; + if (!(parent = node, node = node[i = +right])) return this; + if (!node.length) break; + if (parent[(i + 1) & 1]) retainer = parent, j = i; + } + + // Find the point to remove. + while (node.data !== d) if (!(previous = node, node = node.next)) return this; + if (next = node.next) delete node.next; + + // If there are multiple coincident points, remove just the point. + if (previous) return (next ? previous.next = next : delete previous.next), this; + + // If this is the root point, remove it. + if (!parent) return this._root = next, this; + + // Remove this leaf. + next ? parent[i] = next : delete parent[i]; + + // If the parent now contains exactly one leaf, collapse superfluous parents. + if ((node = parent[0] || parent[1]) + && node === (parent[1] || parent[0]) + && !node.length) { + if (retainer) retainer[j] = node; + else this._root = node; + } + + return this; + } + + function removeAll$2(data) { + for (var i = 0, n = data.length; i < n; ++i) this.remove(data[i]); + return this; + } + + function tree_root$2() { + return this._root; + } + + function tree_size$2() { + var size = 0; + this.visit(function(node) { + if (!node.length) do ++size; while (node = node.next) + }); + return size; + } + + function tree_visit$2(callback) { + var halves = [], q, node = this._root, child, x0, x1; + if (node) halves.push(new Half(node, this._x0, this._x1)); + while (q = halves.pop()) { + if (!callback(node = q.node, x0 = q.x0, x1 = q.x1) && node.length) { + var xm = (x0 + x1) / 2; + if (child = node[1]) halves.push(new Half(child, xm, x1)); + if (child = node[0]) halves.push(new Half(child, x0, xm)); + } + } + return this; + } + + function tree_visitAfter$2(callback) { + var halves = [], next = [], q; + if (this._root) halves.push(new Half(this._root, this._x0, this._x1)); + while (q = halves.pop()) { + var node = q.node; + if (node.length) { + var child, x0 = q.x0, x1 = q.x1, xm = (x0 + x1) / 2; + if (child = node[0]) halves.push(new Half(child, x0, xm)); + if (child = node[1]) halves.push(new Half(child, xm, x1)); + } + next.push(q); + } + while (q = next.pop()) { + callback(q.node, q.x0, q.x1); + } + return this; + } + + function defaultX$2(d) { + return d[0]; + } + + function tree_x$2(_) { + return arguments.length ? (this._x = _, this) : this._x; + } + + function binarytree(nodes, x) { + var tree = new Binarytree(x == null ? defaultX$2 : x, NaN, NaN); + return nodes == null ? tree : tree.addAll(nodes); + } + + function Binarytree(x, x0, x1) { + this._x = x; + this._x0 = x0; + this._x1 = x1; + this._root = undefined; + } + + function leaf_copy$2(leaf) { + var copy = {data: leaf.data}, next = copy; + while (leaf = leaf.next) next = next.next = {data: leaf.data}; + return copy; + } + + var treeProto$2 = binarytree.prototype = Binarytree.prototype; + + treeProto$2.copy = function() { + var copy = new Binarytree(this._x, this._x0, this._x1), + node = this._root, + nodes, + child; + + if (!node) return copy; + + if (!node.length) return copy._root = leaf_copy$2(node), copy; + + nodes = [{source: node, target: copy._root = new Array(2)}]; + while (node = nodes.pop()) { + for (var i = 0; i < 2; ++i) { + if (child = node.source[i]) { + if (child.length) nodes.push({source: child, target: node.target[i] = new Array(2)}); + else node.target[i] = leaf_copy$2(child); + } + } + } + + return copy; + }; + + treeProto$2.add = tree_add$2; + treeProto$2.addAll = addAll$2; + treeProto$2.cover = tree_cover$2; + treeProto$2.data = tree_data$2; + treeProto$2.extent = tree_extent$2; + treeProto$2.find = tree_find$2; + treeProto$2.remove = tree_remove$2; + treeProto$2.removeAll = removeAll$2; + treeProto$2.root = tree_root$2; + treeProto$2.size = tree_size$2; + treeProto$2.visit = tree_visit$2; + treeProto$2.visitAfter = tree_visitAfter$2; + treeProto$2.x = tree_x$2; + + function tree_add$1(d) { + const x = +this._x.call(null, d), + y = +this._y.call(null, d); + return add$1(this.cover(x, y), x, y, d); + } + + function add$1(tree, x, y, d) { + if (isNaN(x) || isNaN(y)) return tree; // ignore invalid points + + var parent, + node = tree._root, + leaf = {data: d}, + x0 = tree._x0, + y0 = tree._y0, + x1 = tree._x1, + y1 = tree._y1, + xm, + ym, + xp, + yp, + right, + bottom, + i, + j; + + // If the tree is empty, initialize the root as a leaf. + if (!node) return tree._root = leaf, tree; + + // Find the existing leaf for the new point, or add it. + while (node.length) { + if (right = x >= (xm = (x0 + x1) / 2)) x0 = xm; else x1 = xm; + if (bottom = y >= (ym = (y0 + y1) / 2)) y0 = ym; else y1 = ym; + if (parent = node, !(node = node[i = bottom << 1 | right])) return parent[i] = leaf, tree; + } + + // Is the new point is exactly coincident with the existing point? + xp = +tree._x.call(null, node.data); + yp = +tree._y.call(null, node.data); + if (x === xp && y === yp) return leaf.next = node, parent ? parent[i] = leaf : tree._root = leaf, tree; + + // Otherwise, split the leaf node until the old and new point are separated. + do { + parent = parent ? parent[i] = new Array(4) : tree._root = new Array(4); + if (right = x >= (xm = (x0 + x1) / 2)) x0 = xm; else x1 = xm; + if (bottom = y >= (ym = (y0 + y1) / 2)) y0 = ym; else y1 = ym; + } while ((i = bottom << 1 | right) === (j = (yp >= ym) << 1 | (xp >= xm))); + return parent[j] = node, parent[i] = leaf, tree; + } + + function addAll$1(data) { + var d, i, n = data.length, + x, + y, + xz = new Array(n), + yz = new Array(n), + x0 = Infinity, + y0 = Infinity, + x1 = -Infinity, + y1 = -Infinity; + + // Compute the points and their extent. + for (i = 0; i < n; ++i) { + if (isNaN(x = +this._x.call(null, d = data[i])) || isNaN(y = +this._y.call(null, d))) continue; + xz[i] = x; + yz[i] = y; + if (x < x0) x0 = x; + if (x > x1) x1 = x; + if (y < y0) y0 = y; + if (y > y1) y1 = y; + } + + // If there were no (valid) points, abort. + if (x0 > x1 || y0 > y1) return this; + + // Expand the tree to cover the new points. + this.cover(x0, y0).cover(x1, y1); + + // Add the new points. + for (i = 0; i < n; ++i) { + add$1(this, xz[i], yz[i], data[i]); + } + + return this; + } + + function tree_cover$1(x, y) { + if (isNaN(x = +x) || isNaN(y = +y)) return this; // ignore invalid points + + var x0 = this._x0, + y0 = this._y0, + x1 = this._x1, + y1 = this._y1; + + // If the quadtree has no extent, initialize them. + // Integer extent are necessary so that if we later double the extent, + // the existing quadrant boundaries don’t change due to floating point error! + if (isNaN(x0)) { + x1 = (x0 = Math.floor(x)) + 1; + y1 = (y0 = Math.floor(y)) + 1; + } + + // Otherwise, double repeatedly to cover. + else { + var z = x1 - x0 || 1, + node = this._root, + parent, + i; + + while (x0 > x || x >= x1 || y0 > y || y >= y1) { + i = (y < y0) << 1 | (x < x0); + parent = new Array(4), parent[i] = node, node = parent, z *= 2; + switch (i) { + case 0: x1 = x0 + z, y1 = y0 + z; break; + case 1: x0 = x1 - z, y1 = y0 + z; break; + case 2: x1 = x0 + z, y0 = y1 - z; break; + case 3: x0 = x1 - z, y0 = y1 - z; break; + } + } + + if (this._root && this._root.length) this._root = node; + } + + this._x0 = x0; + this._y0 = y0; + this._x1 = x1; + this._y1 = y1; + return this; + } + + function tree_data$1() { + var data = []; + this.visit(function(node) { + if (!node.length) do data.push(node.data); while (node = node.next) + }); + return data; + } + + function tree_extent$1(_) { + return arguments.length + ? this.cover(+_[0][0], +_[0][1]).cover(+_[1][0], +_[1][1]) + : isNaN(this._x0) ? undefined : [[this._x0, this._y0], [this._x1, this._y1]]; + } + + function Quad(node, x0, y0, x1, y1) { + this.node = node; + this.x0 = x0; + this.y0 = y0; + this.x1 = x1; + this.y1 = y1; + } + + function tree_find$1(x, y, radius) { + var data, + x0 = this._x0, + y0 = this._y0, + x1, + y1, + x2, + y2, + x3 = this._x1, + y3 = this._y1, + quads = [], + node = this._root, + q, + i; + + if (node) quads.push(new Quad(node, x0, y0, x3, y3)); + if (radius == null) radius = Infinity; + else { + x0 = x - radius, y0 = y - radius; + x3 = x + radius, y3 = y + radius; + radius *= radius; + } + + while (q = quads.pop()) { + + // Stop searching if this quadrant can’t contain a closer node. + if (!(node = q.node) + || (x1 = q.x0) > x3 + || (y1 = q.y0) > y3 + || (x2 = q.x1) < x0 + || (y2 = q.y1) < y0) continue; + + // Bisect the current quadrant. + if (node.length) { + var xm = (x1 + x2) / 2, + ym = (y1 + y2) / 2; + + quads.push( + new Quad(node[3], xm, ym, x2, y2), + new Quad(node[2], x1, ym, xm, y2), + new Quad(node[1], xm, y1, x2, ym), + new Quad(node[0], x1, y1, xm, ym) + ); + + // Visit the closest quadrant first. + if (i = (y >= ym) << 1 | (x >= xm)) { + q = quads[quads.length - 1]; + quads[quads.length - 1] = quads[quads.length - 1 - i]; + quads[quads.length - 1 - i] = q; + } + } + + // Visit this point. (Visiting coincident points isn’t necessary!) + else { + var dx = x - +this._x.call(null, node.data), + dy = y - +this._y.call(null, node.data), + d2 = dx * dx + dy * dy; + if (d2 < radius) { + var d = Math.sqrt(radius = d2); + x0 = x - d, y0 = y - d; + x3 = x + d, y3 = y + d; + data = node.data; + } + } + } + + return data; + } + + function tree_remove$1(d) { + if (isNaN(x = +this._x.call(null, d)) || isNaN(y = +this._y.call(null, d))) return this; // ignore invalid points + + var parent, + node = this._root, + retainer, + previous, + next, + x0 = this._x0, + y0 = this._y0, + x1 = this._x1, + y1 = this._y1, + x, + y, + xm, + ym, + right, + bottom, + i, + j; + + // If the tree is empty, initialize the root as a leaf. + if (!node) return this; + + // Find the leaf node for the point. + // While descending, also retain the deepest parent with a non-removed sibling. + if (node.length) while (true) { + if (right = x >= (xm = (x0 + x1) / 2)) x0 = xm; else x1 = xm; + if (bottom = y >= (ym = (y0 + y1) / 2)) y0 = ym; else y1 = ym; + if (!(parent = node, node = node[i = bottom << 1 | right])) return this; + if (!node.length) break; + if (parent[(i + 1) & 3] || parent[(i + 2) & 3] || parent[(i + 3) & 3]) retainer = parent, j = i; + } + + // Find the point to remove. + while (node.data !== d) if (!(previous = node, node = node.next)) return this; + if (next = node.next) delete node.next; + + // If there are multiple coincident points, remove just the point. + if (previous) return (next ? previous.next = next : delete previous.next), this; + + // If this is the root point, remove it. + if (!parent) return this._root = next, this; + + // Remove this leaf. + next ? parent[i] = next : delete parent[i]; + + // If the parent now contains exactly one leaf, collapse superfluous parents. + if ((node = parent[0] || parent[1] || parent[2] || parent[3]) + && node === (parent[3] || parent[2] || parent[1] || parent[0]) + && !node.length) { + if (retainer) retainer[j] = node; + else this._root = node; + } + + return this; + } + + function removeAll$1(data) { + for (var i = 0, n = data.length; i < n; ++i) this.remove(data[i]); + return this; + } + + function tree_root$1() { + return this._root; + } + + function tree_size$1() { + var size = 0; + this.visit(function(node) { + if (!node.length) do ++size; while (node = node.next) + }); + return size; + } + + function tree_visit$1(callback) { + var quads = [], q, node = this._root, child, x0, y0, x1, y1; + if (node) quads.push(new Quad(node, this._x0, this._y0, this._x1, this._y1)); + while (q = quads.pop()) { + if (!callback(node = q.node, x0 = q.x0, y0 = q.y0, x1 = q.x1, y1 = q.y1) && node.length) { + var xm = (x0 + x1) / 2, ym = (y0 + y1) / 2; + if (child = node[3]) quads.push(new Quad(child, xm, ym, x1, y1)); + if (child = node[2]) quads.push(new Quad(child, x0, ym, xm, y1)); + if (child = node[1]) quads.push(new Quad(child, xm, y0, x1, ym)); + if (child = node[0]) quads.push(new Quad(child, x0, y0, xm, ym)); + } + } + return this; + } + + function tree_visitAfter$1(callback) { + var quads = [], next = [], q; + if (this._root) quads.push(new Quad(this._root, this._x0, this._y0, this._x1, this._y1)); + while (q = quads.pop()) { + var node = q.node; + if (node.length) { + var child, x0 = q.x0, y0 = q.y0, x1 = q.x1, y1 = q.y1, xm = (x0 + x1) / 2, ym = (y0 + y1) / 2; + if (child = node[0]) quads.push(new Quad(child, x0, y0, xm, ym)); + if (child = node[1]) quads.push(new Quad(child, xm, y0, x1, ym)); + if (child = node[2]) quads.push(new Quad(child, x0, ym, xm, y1)); + if (child = node[3]) quads.push(new Quad(child, xm, ym, x1, y1)); + } + next.push(q); + } + while (q = next.pop()) { + callback(q.node, q.x0, q.y0, q.x1, q.y1); + } + return this; + } + + function defaultX$1(d) { + return d[0]; + } + + function tree_x$1(_) { + return arguments.length ? (this._x = _, this) : this._x; + } + + function defaultY$1(d) { + return d[1]; + } + + function tree_y$1(_) { + return arguments.length ? (this._y = _, this) : this._y; + } + + function quadtree(nodes, x, y) { + var tree = new Quadtree(x == null ? defaultX$1 : x, y == null ? defaultY$1 : y, NaN, NaN, NaN, NaN); + return nodes == null ? tree : tree.addAll(nodes); + } + + function Quadtree(x, y, x0, y0, x1, y1) { + this._x = x; + this._y = y; + this._x0 = x0; + this._y0 = y0; + this._x1 = x1; + this._y1 = y1; + this._root = undefined; + } + + function leaf_copy$1(leaf) { + var copy = {data: leaf.data}, next = copy; + while (leaf = leaf.next) next = next.next = {data: leaf.data}; + return copy; + } + + var treeProto$1 = quadtree.prototype = Quadtree.prototype; + + treeProto$1.copy = function() { + var copy = new Quadtree(this._x, this._y, this._x0, this._y0, this._x1, this._y1), + node = this._root, + nodes, + child; + + if (!node) return copy; + + if (!node.length) return copy._root = leaf_copy$1(node), copy; + + nodes = [{source: node, target: copy._root = new Array(4)}]; + while (node = nodes.pop()) { + for (var i = 0; i < 4; ++i) { + if (child = node.source[i]) { + if (child.length) nodes.push({source: child, target: node.target[i] = new Array(4)}); + else node.target[i] = leaf_copy$1(child); + } + } + } + + return copy; + }; + + treeProto$1.add = tree_add$1; + treeProto$1.addAll = addAll$1; + treeProto$1.cover = tree_cover$1; + treeProto$1.data = tree_data$1; + treeProto$1.extent = tree_extent$1; + treeProto$1.find = tree_find$1; + treeProto$1.remove = tree_remove$1; + treeProto$1.removeAll = removeAll$1; + treeProto$1.root = tree_root$1; + treeProto$1.size = tree_size$1; + treeProto$1.visit = tree_visit$1; + treeProto$1.visitAfter = tree_visitAfter$1; + treeProto$1.x = tree_x$1; + treeProto$1.y = tree_y$1; + + function tree_add(d) { + const x = +this._x.call(null, d), + y = +this._y.call(null, d), + z = +this._z.call(null, d); + return add(this.cover(x, y, z), x, y, z, d); + } + + function add(tree, x, y, z, d) { + if (isNaN(x) || isNaN(y) || isNaN(z)) return tree; // ignore invalid points + + var parent, + node = tree._root, + leaf = {data: d}, + x0 = tree._x0, + y0 = tree._y0, + z0 = tree._z0, + x1 = tree._x1, + y1 = tree._y1, + z1 = tree._z1, + xm, + ym, + zm, + xp, + yp, + zp, + right, + bottom, + deep, + i, + j; + + // If the tree is empty, initialize the root as a leaf. + if (!node) return tree._root = leaf, tree; + + // Find the existing leaf for the new point, or add it. + while (node.length) { + if (right = x >= (xm = (x0 + x1) / 2)) x0 = xm; else x1 = xm; + if (bottom = y >= (ym = (y0 + y1) / 2)) y0 = ym; else y1 = ym; + if (deep = z >= (zm = (z0 + z1) / 2)) z0 = zm; else z1 = zm; + if (parent = node, !(node = node[i = deep << 2 | bottom << 1 | right])) return parent[i] = leaf, tree; + } + + // Is the new point is exactly coincident with the existing point? + xp = +tree._x.call(null, node.data); + yp = +tree._y.call(null, node.data); + zp = +tree._z.call(null, node.data); + if (x === xp && y === yp && z === zp) return leaf.next = node, parent ? parent[i] = leaf : tree._root = leaf, tree; + + // Otherwise, split the leaf node until the old and new point are separated. + do { + parent = parent ? parent[i] = new Array(8) : tree._root = new Array(8); + if (right = x >= (xm = (x0 + x1) / 2)) x0 = xm; else x1 = xm; + if (bottom = y >= (ym = (y0 + y1) / 2)) y0 = ym; else y1 = ym; + if (deep = z >= (zm = (z0 + z1) / 2)) z0 = zm; else z1 = zm; + } while ((i = deep << 2 | bottom << 1 | right) === (j = (zp >= zm) << 2 | (yp >= ym) << 1 | (xp >= xm))); + return parent[j] = node, parent[i] = leaf, tree; + } + + function addAll(data) { + if (!Array.isArray(data)) data = Array.from(data); + const n = data.length; + const xz = new Float64Array(n); + const yz = new Float64Array(n); + const zz = new Float64Array(n); + let x0 = Infinity, + y0 = Infinity, + z0 = Infinity, + x1 = -Infinity, + y1 = -Infinity, + z1 = -Infinity; + + // Compute the points and their extent. + for (let i = 0, d, x, y, z; i < n; ++i) { + if (isNaN(x = +this._x.call(null, d = data[i])) || isNaN(y = +this._y.call(null, d)) || isNaN(z = +this._z.call(null, d))) continue; + xz[i] = x; + yz[i] = y; + zz[i] = z; + if (x < x0) x0 = x; + if (x > x1) x1 = x; + if (y < y0) y0 = y; + if (y > y1) y1 = y; + if (z < z0) z0 = z; + if (z > z1) z1 = z; + } + + // If there were no (valid) points, abort. + if (x0 > x1 || y0 > y1 || z0 > z1) return this; + + // Expand the tree to cover the new points. + this.cover(x0, y0, z0).cover(x1, y1, z1); + + // Add the new points. + for (let i = 0; i < n; ++i) { + add(this, xz[i], yz[i], zz[i], data[i]); + } + + return this; + } + + function tree_cover(x, y, z) { + if (isNaN(x = +x) || isNaN(y = +y) || isNaN(z = +z)) return this; // ignore invalid points + + var x0 = this._x0, + y0 = this._y0, + z0 = this._z0, + x1 = this._x1, + y1 = this._y1, + z1 = this._z1; + + // If the octree has no extent, initialize them. + // Integer extent are necessary so that if we later double the extent, + // the existing octant boundaries don’t change due to floating point error! + if (isNaN(x0)) { + x1 = (x0 = Math.floor(x)) + 1; + y1 = (y0 = Math.floor(y)) + 1; + z1 = (z0 = Math.floor(z)) + 1; + } + + // Otherwise, double repeatedly to cover. + else { + var t = x1 - x0 || 1, + node = this._root, + parent, + i; + + while (x0 > x || x >= x1 || y0 > y || y >= y1 || z0 > z || z >= z1) { + i = (z < z0) << 2 | (y < y0) << 1 | (x < x0); + parent = new Array(8), parent[i] = node, node = parent, t *= 2; + switch (i) { + case 0: x1 = x0 + t, y1 = y0 + t, z1 = z0 + t; break; + case 1: x0 = x1 - t, y1 = y0 + t, z1 = z0 + t; break; + case 2: x1 = x0 + t, y0 = y1 - t, z1 = z0 + t; break; + case 3: x0 = x1 - t, y0 = y1 - t, z1 = z0 + t; break; + case 4: x1 = x0 + t, y1 = y0 + t, z0 = z1 - t; break; + case 5: x0 = x1 - t, y1 = y0 + t, z0 = z1 - t; break; + case 6: x1 = x0 + t, y0 = y1 - t, z0 = z1 - t; break; + case 7: x0 = x1 - t, y0 = y1 - t, z0 = z1 - t; break; + } + } + + if (this._root && this._root.length) this._root = node; + } + + this._x0 = x0; + this._y0 = y0; + this._z0 = z0; + this._x1 = x1; + this._y1 = y1; + this._z1 = z1; + return this; + } + + function tree_data() { + var data = []; + this.visit(function(node) { + if (!node.length) do data.push(node.data); while (node = node.next) + }); + return data; + } + + function tree_extent(_) { + return arguments.length + ? this.cover(+_[0][0], +_[0][1], +_[0][2]).cover(+_[1][0], +_[1][1], +_[1][2]) + : isNaN(this._x0) ? undefined : [[this._x0, this._y0, this._z0], [this._x1, this._y1, this._z1]]; + } + + function Octant(node, x0, y0, z0, x1, y1, z1) { + this.node = node; + this.x0 = x0; + this.y0 = y0; + this.z0 = z0; + this.x1 = x1; + this.y1 = y1; + this.z1 = z1; + } + + function tree_find(x, y, z, radius) { + var data, + x0 = this._x0, + y0 = this._y0, + z0 = this._z0, + x1, + y1, + z1, + x2, + y2, + z2, + x3 = this._x1, + y3 = this._y1, + z3 = this._z1, + octs = [], + node = this._root, + q, + i; + + if (node) octs.push(new Octant(node, x0, y0, z0, x3, y3, z3)); + if (radius == null) radius = Infinity; + else { + x0 = x - radius, y0 = y - radius, z0 = z - radius; + x3 = x + radius, y3 = y + radius, z3 = z + radius; + radius *= radius; + } + + while (q = octs.pop()) { + + // Stop searching if this octant can’t contain a closer node. + if (!(node = q.node) + || (x1 = q.x0) > x3 + || (y1 = q.y0) > y3 + || (z1 = q.z0) > z3 + || (x2 = q.x1) < x0 + || (y2 = q.y1) < y0 + || (z2 = q.z1) < z0) continue; + + // Bisect the current octant. + if (node.length) { + var xm = (x1 + x2) / 2, + ym = (y1 + y2) / 2, + zm = (z1 + z2) / 2; + + octs.push( + new Octant(node[7], xm, ym, zm, x2, y2, z2), + new Octant(node[6], x1, ym, zm, xm, y2, z2), + new Octant(node[5], xm, y1, zm, x2, ym, z2), + new Octant(node[4], x1, y1, zm, xm, ym, z2), + new Octant(node[3], xm, ym, z1, x2, y2, zm), + new Octant(node[2], x1, ym, z1, xm, y2, zm), + new Octant(node[1], xm, y1, z1, x2, ym, zm), + new Octant(node[0], x1, y1, z1, xm, ym, zm) + ); + + // Visit the closest octant first. + if (i = (z >= zm) << 2 | (y >= ym) << 1 | (x >= xm)) { + q = octs[octs.length - 1]; + octs[octs.length - 1] = octs[octs.length - 1 - i]; + octs[octs.length - 1 - i] = q; + } + } + + // Visit this point. (Visiting coincident points isn’t necessary!) + else { + var dx = x - +this._x.call(null, node.data), + dy = y - +this._y.call(null, node.data), + dz = z - +this._z.call(null, node.data), + d2 = dx * dx + dy * dy + dz * dz; + if (d2 < radius) { + var d = Math.sqrt(radius = d2); + x0 = x - d, y0 = y - d, z0 = z - d; + x3 = x + d, y3 = y + d, z3 = z + d; + data = node.data; + } + } + } + + return data; + } + + function tree_remove(d) { + if (isNaN(x = +this._x.call(null, d)) || isNaN(y = +this._y.call(null, d)) || isNaN(z = +this._z.call(null, d))) return this; // ignore invalid points + + var parent, + node = this._root, + retainer, + previous, + next, + x0 = this._x0, + y0 = this._y0, + z0 = this._z0, + x1 = this._x1, + y1 = this._y1, + z1 = this._z1, + x, + y, + z, + xm, + ym, + zm, + right, + bottom, + deep, + i, + j; + + // If the tree is empty, initialize the root as a leaf. + if (!node) return this; + + // Find the leaf node for the point. + // While descending, also retain the deepest parent with a non-removed sibling. + if (node.length) while (true) { + if (right = x >= (xm = (x0 + x1) / 2)) x0 = xm; else x1 = xm; + if (bottom = y >= (ym = (y0 + y1) / 2)) y0 = ym; else y1 = ym; + if (deep = z >= (zm = (z0 + z1) / 2)) z0 = zm; else z1 = zm; + if (!(parent = node, node = node[i = deep << 2 | bottom << 1 | right])) return this; + if (!node.length) break; + if (parent[(i + 1) & 7] || parent[(i + 2) & 7] || parent[(i + 3) & 7] || parent[(i + 4) & 7] || parent[(i + 5) & 7] || parent[(i + 6) & 7] || parent[(i + 7) & 7]) retainer = parent, j = i; + } + + // Find the point to remove. + while (node.data !== d) if (!(previous = node, node = node.next)) return this; + if (next = node.next) delete node.next; + + // If there are multiple coincident points, remove just the point. + if (previous) return (next ? previous.next = next : delete previous.next), this; + + // If this is the root point, remove it. + if (!parent) return this._root = next, this; + + // Remove this leaf. + next ? parent[i] = next : delete parent[i]; + + // If the parent now contains exactly one leaf, collapse superfluous parents. + if ((node = parent[0] || parent[1] || parent[2] || parent[3] || parent[4] || parent[5] || parent[6] || parent[7]) + && node === (parent[7] || parent[6] || parent[5] || parent[4] || parent[3] || parent[2] || parent[1] || parent[0]) + && !node.length) { + if (retainer) retainer[j] = node; + else this._root = node; + } + + return this; + } + + function removeAll(data) { + for (var i = 0, n = data.length; i < n; ++i) this.remove(data[i]); + return this; + } + + function tree_root() { + return this._root; + } + + function tree_size() { + var size = 0; + this.visit(function(node) { + if (!node.length) do ++size; while (node = node.next) + }); + return size; + } + + function tree_visit(callback) { + var octs = [], q, node = this._root, child, x0, y0, z0, x1, y1, z1; + if (node) octs.push(new Octant(node, this._x0, this._y0, this._z0, this._x1, this._y1, this._z1)); + while (q = octs.pop()) { + if (!callback(node = q.node, x0 = q.x0, y0 = q.y0, z0 = q.z0, x1 = q.x1, y1 = q.y1, z1 = q.z1) && node.length) { + var xm = (x0 + x1) / 2, ym = (y0 + y1) / 2, zm = (z0 + z1) / 2; + if (child = node[7]) octs.push(new Octant(child, xm, ym, zm, x1, y1, z1)); + if (child = node[6]) octs.push(new Octant(child, x0, ym, zm, xm, y1, z1)); + if (child = node[5]) octs.push(new Octant(child, xm, y0, zm, x1, ym, z1)); + if (child = node[4]) octs.push(new Octant(child, x0, y0, zm, xm, ym, z1)); + if (child = node[3]) octs.push(new Octant(child, xm, ym, z0, x1, y1, zm)); + if (child = node[2]) octs.push(new Octant(child, x0, ym, z0, xm, y1, zm)); + if (child = node[1]) octs.push(new Octant(child, xm, y0, z0, x1, ym, zm)); + if (child = node[0]) octs.push(new Octant(child, x0, y0, z0, xm, ym, zm)); + } + } + return this; + } + + function tree_visitAfter(callback) { + var octs = [], next = [], q; + if (this._root) octs.push(new Octant(this._root, this._x0, this._y0, this._z0, this._x1, this._y1, this._z1)); + while (q = octs.pop()) { + var node = q.node; + if (node.length) { + var child, x0 = q.x0, y0 = q.y0, z0 = q.z0, x1 = q.x1, y1 = q.y1, z1 = q.z1, xm = (x0 + x1) / 2, ym = (y0 + y1) / 2, zm = (z0 + z1) / 2; + if (child = node[0]) octs.push(new Octant(child, x0, y0, z0, xm, ym, zm)); + if (child = node[1]) octs.push(new Octant(child, xm, y0, z0, x1, ym, zm)); + if (child = node[2]) octs.push(new Octant(child, x0, ym, z0, xm, y1, zm)); + if (child = node[3]) octs.push(new Octant(child, xm, ym, z0, x1, y1, zm)); + if (child = node[4]) octs.push(new Octant(child, x0, y0, zm, xm, ym, z1)); + if (child = node[5]) octs.push(new Octant(child, xm, y0, zm, x1, ym, z1)); + if (child = node[6]) octs.push(new Octant(child, x0, ym, zm, xm, y1, z1)); + if (child = node[7]) octs.push(new Octant(child, xm, ym, zm, x1, y1, z1)); + } + next.push(q); + } + while (q = next.pop()) { + callback(q.node, q.x0, q.y0, q.z0, q.x1, q.y1, q.z1); + } + return this; + } + + function defaultX(d) { + return d[0]; + } + + function tree_x(_) { + return arguments.length ? (this._x = _, this) : this._x; + } + + function defaultY(d) { + return d[1]; + } + + function tree_y(_) { + return arguments.length ? (this._y = _, this) : this._y; + } + + function defaultZ(d) { + return d[2]; + } + + function tree_z(_) { + return arguments.length ? (this._z = _, this) : this._z; + } + + function octree(nodes, x, y, z) { + var tree = new Octree(x == null ? defaultX : x, y == null ? defaultY : y, z == null ? defaultZ : z, NaN, NaN, NaN, NaN, NaN, NaN); + return nodes == null ? tree : tree.addAll(nodes); + } + + function Octree(x, y, z, x0, y0, z0, x1, y1, z1) { + this._x = x; + this._y = y; + this._z = z; + this._x0 = x0; + this._y0 = y0; + this._z0 = z0; + this._x1 = x1; + this._y1 = y1; + this._z1 = z1; + this._root = undefined; + } + + function leaf_copy(leaf) { + var copy = {data: leaf.data}, next = copy; + while (leaf = leaf.next) next = next.next = {data: leaf.data}; + return copy; + } + + var treeProto = octree.prototype = Octree.prototype; + + treeProto.copy = function() { + var copy = new Octree(this._x, this._y, this._z, this._x0, this._y0, this._z0, this._x1, this._y1, this._z1), + node = this._root, + nodes, + child; + + if (!node) return copy; + + if (!node.length) return copy._root = leaf_copy(node), copy; + + nodes = [{source: node, target: copy._root = new Array(8)}]; + while (node = nodes.pop()) { + for (var i = 0; i < 8; ++i) { + if (child = node.source[i]) { + if (child.length) nodes.push({source: child, target: node.target[i] = new Array(8)}); + else node.target[i] = leaf_copy(child); + } + } + } + + return copy; + }; + + treeProto.add = tree_add; + treeProto.addAll = addAll; + treeProto.cover = tree_cover; + treeProto.data = tree_data; + treeProto.extent = tree_extent; + treeProto.find = tree_find; + treeProto.remove = tree_remove; + treeProto.removeAll = removeAll; + treeProto.root = tree_root; + treeProto.size = tree_size; + treeProto.visit = tree_visit; + treeProto.visitAfter = tree_visitAfter; + treeProto.x = tree_x; + treeProto.y = tree_y; + treeProto.z = tree_z; + + function constant(x) { + return function() { + return x; + }; + } + + function jiggle(random) { + return (random() - 0.5) * 1e-6; + } + + function index$1(d) { + return d.index; + } + + function find(nodeById, nodeId) { + var node = nodeById.get(nodeId); + if (!node) throw new Error("node not found: " + nodeId); + return node; + } + + function d3ForceLink(links) { + var id = index$1, + strength = defaultStrength, + strengths, + distance = constant(30), + distances, + nodes, + nDim, + count, + bias, + random, + iterations = 1; + + if (links == null) links = []; + + function defaultStrength(link) { + return 1 / Math.min(count[link.source.index], count[link.target.index]); + } + + function force(alpha) { + for (var k = 0, n = links.length; k < iterations; ++k) { + for (var i = 0, link, source, target, x = 0, y = 0, z = 0, l, b; i < n; ++i) { + link = links[i], source = link.source, target = link.target; + x = target.x + target.vx - source.x - source.vx || jiggle(random); + if (nDim > 1) { y = target.y + target.vy - source.y - source.vy || jiggle(random); } + if (nDim > 2) { z = target.z + target.vz - source.z - source.vz || jiggle(random); } + l = Math.sqrt(x * x + y * y + z * z); + l = (l - distances[i]) / l * alpha * strengths[i]; + x *= l, y *= l, z *= l; + + target.vx -= x * (b = bias[i]); + if (nDim > 1) { target.vy -= y * b; } + if (nDim > 2) { target.vz -= z * b; } + + source.vx += x * (b = 1 - b); + if (nDim > 1) { source.vy += y * b; } + if (nDim > 2) { source.vz += z * b; } + } + } + } + + function initialize() { + if (!nodes) return; + + var i, + n = nodes.length, + m = links.length, + nodeById = new Map(nodes.map((d, i) => [id(d, i, nodes), d])), + link; + + for (i = 0, count = new Array(n); i < m; ++i) { + link = links[i], link.index = i; + if (typeof link.source !== "object") link.source = find(nodeById, link.source); + if (typeof link.target !== "object") link.target = find(nodeById, link.target); + count[link.source.index] = (count[link.source.index] || 0) + 1; + count[link.target.index] = (count[link.target.index] || 0) + 1; + } + + for (i = 0, bias = new Array(m); i < m; ++i) { + link = links[i], bias[i] = count[link.source.index] / (count[link.source.index] + count[link.target.index]); + } + + strengths = new Array(m), initializeStrength(); + distances = new Array(m), initializeDistance(); + } + + function initializeStrength() { + if (!nodes) return; + + for (var i = 0, n = links.length; i < n; ++i) { + strengths[i] = +strength(links[i], i, links); + } + } + + function initializeDistance() { + if (!nodes) return; + + for (var i = 0, n = links.length; i < n; ++i) { + distances[i] = +distance(links[i], i, links); + } + } + + force.initialize = function(_nodes, ...args) { + nodes = _nodes; + random = args.find(arg => typeof arg === 'function') || Math.random; + nDim = args.find(arg => [1, 2, 3].includes(arg)) || 2; + initialize(); + }; + + force.links = function(_) { + return arguments.length ? (links = _, initialize(), force) : links; + }; + + force.id = function(_) { + return arguments.length ? (id = _, force) : id; + }; + + force.iterations = function(_) { + return arguments.length ? (iterations = +_, force) : iterations; + }; + + force.strength = function(_) { + return arguments.length ? (strength = typeof _ === "function" ? _ : constant(+_), initializeStrength(), force) : strength; + }; + + force.distance = function(_) { + return arguments.length ? (distance = typeof _ === "function" ? _ : constant(+_), initializeDistance(), force) : distance; + }; + + return force; + } + + // https://en.wikipedia.org/wiki/Linear_congruential_generator#Parameters_in_common_use + const a = 1664525; + const c = 1013904223; + const m = 4294967296; // 2^32 + + function lcg() { + let s = 1; + return () => (s = (a * s + c) % m) / m; + } + + var MAX_DIMENSIONS = 3; + + function x(d) { + return d.x; + } + + function y(d) { + return d.y; + } + + function z(d) { + return d.z; + } + + var initialRadius = 10, + initialAngleRoll = Math.PI * (3 - Math.sqrt(5)), // Golden ratio angle + initialAngleYaw = Math.PI * 20 / (9 + Math.sqrt(221)); // Markov irrational number + + function d3ForceSimulation(nodes, numDimensions) { + numDimensions = numDimensions || 2; + + var nDim = Math.min(MAX_DIMENSIONS, Math.max(1, Math.round(numDimensions))), + simulation, + alpha = 1, + alphaMin = 0.001, + alphaDecay = 1 - Math.pow(alphaMin, 1 / 300), + alphaTarget = 0, + velocityDecay = 0.6, + forces = new Map(), + stepper = timer(step), + event = dispatch("tick", "end"), + random = lcg(); + + if (nodes == null) nodes = []; + + function step() { + tick(); + event.call("tick", simulation); + if (alpha < alphaMin) { + stepper.stop(); + event.call("end", simulation); + } + } + + function tick(iterations) { + var i, n = nodes.length, node; + + if (iterations === undefined) iterations = 1; + + for (var k = 0; k < iterations; ++k) { + alpha += (alphaTarget - alpha) * alphaDecay; + + forces.forEach(function (force) { + force(alpha); + }); + + for (i = 0; i < n; ++i) { + node = nodes[i]; + if (node.fx == null) node.x += node.vx *= velocityDecay; + else node.x = node.fx, node.vx = 0; + if (nDim > 1) { + if (node.fy == null) node.y += node.vy *= velocityDecay; + else node.y = node.fy, node.vy = 0; + } + if (nDim > 2) { + if (node.fz == null) node.z += node.vz *= velocityDecay; + else node.z = node.fz, node.vz = 0; + } + } + } + + return simulation; + } + + function initializeNodes() { + for (var i = 0, n = nodes.length, node; i < n; ++i) { + node = nodes[i], node.index = i; + if (node.fx != null) node.x = node.fx; + if (node.fy != null) node.y = node.fy; + if (node.fz != null) node.z = node.fz; + if (isNaN(node.x) || (nDim > 1 && isNaN(node.y)) || (nDim > 2 && isNaN(node.z))) { + var radius = initialRadius * (nDim > 2 ? Math.cbrt(0.5 + i) : (nDim > 1 ? Math.sqrt(0.5 + i) : i)), + rollAngle = i * initialAngleRoll, + yawAngle = i * initialAngleYaw; + + if (nDim === 1) { + node.x = radius; + } else if (nDim === 2) { + node.x = radius * Math.cos(rollAngle); + node.y = radius * Math.sin(rollAngle); + } else { // 3 dimensions: use spherical distribution along 2 irrational number angles + node.x = radius * Math.sin(rollAngle) * Math.cos(yawAngle); + node.y = radius * Math.cos(rollAngle); + node.z = radius * Math.sin(rollAngle) * Math.sin(yawAngle); + } + } + if (isNaN(node.vx) || (nDim > 1 && isNaN(node.vy)) || (nDim > 2 && isNaN(node.vz))) { + node.vx = 0; + if (nDim > 1) { node.vy = 0; } + if (nDim > 2) { node.vz = 0; } + } + } + } + + function initializeForce(force) { + if (force.initialize) force.initialize(nodes, random, nDim); + return force; + } + + initializeNodes(); + + return simulation = { + tick: tick, + + restart: function() { + return stepper.restart(step), simulation; + }, + + stop: function() { + return stepper.stop(), simulation; + }, + + numDimensions: function(_) { + return arguments.length + ? (nDim = Math.min(MAX_DIMENSIONS, Math.max(1, Math.round(_))), forces.forEach(initializeForce), simulation) + : nDim; + }, + + nodes: function(_) { + return arguments.length ? (nodes = _, initializeNodes(), forces.forEach(initializeForce), simulation) : nodes; + }, + + alpha: function(_) { + return arguments.length ? (alpha = +_, simulation) : alpha; + }, + + alphaMin: function(_) { + return arguments.length ? (alphaMin = +_, simulation) : alphaMin; + }, + + alphaDecay: function(_) { + return arguments.length ? (alphaDecay = +_, simulation) : +alphaDecay; + }, + + alphaTarget: function(_) { + return arguments.length ? (alphaTarget = +_, simulation) : alphaTarget; + }, + + velocityDecay: function(_) { + return arguments.length ? (velocityDecay = 1 - _, simulation) : 1 - velocityDecay; + }, + + randomSource: function(_) { + return arguments.length ? (random = _, forces.forEach(initializeForce), simulation) : random; + }, + + force: function(name, _) { + return arguments.length > 1 ? ((_ == null ? forces.delete(name) : forces.set(name, initializeForce(_))), simulation) : forces.get(name); + }, + + find: function() { + var args = Array.prototype.slice.call(arguments); + var x = args.shift() || 0, + y = (nDim > 1 ? args.shift() : null) || 0, + z = (nDim > 2 ? args.shift() : null) || 0, + radius = args.shift() || Infinity; + + var i = 0, + n = nodes.length, + dx, + dy, + dz, + d2, + node, + closest; + + radius *= radius; + + for (i = 0; i < n; ++i) { + node = nodes[i]; + dx = x - node.x; + dy = y - (node.y || 0); + dz = z - (node.z ||0); + d2 = dx * dx + dy * dy + dz * dz; + if (d2 < radius) closest = node, radius = d2; + } + + return closest; + }, + + on: function(name, _) { + return arguments.length > 1 ? (event.on(name, _), simulation) : event.on(name); + } + }; + } + + function d3ForceManyBody() { + var nodes, + nDim, + node, + random, + alpha, + strength = constant(-30), + strengths, + distanceMin2 = 1, + distanceMax2 = Infinity, + theta2 = 0.81; + + function force(_) { + var i, + n = nodes.length, + tree = + (nDim === 1 ? binarytree(nodes, x) + :(nDim === 2 ? quadtree(nodes, x, y) + :(nDim === 3 ? octree(nodes, x, y, z) + :null + ))).visitAfter(accumulate); + + for (alpha = _, i = 0; i < n; ++i) node = nodes[i], tree.visit(apply); + } + + function initialize() { + if (!nodes) return; + var i, n = nodes.length, node; + strengths = new Array(n); + for (i = 0; i < n; ++i) node = nodes[i], strengths[node.index] = +strength(node, i, nodes); + } + + function accumulate(treeNode) { + var strength = 0, q, c, weight = 0, x, y, z, i; + var numChildren = treeNode.length; + + // For internal nodes, accumulate forces from children. + if (numChildren) { + for (x = y = z = i = 0; i < numChildren; ++i) { + if ((q = treeNode[i]) && (c = Math.abs(q.value))) { + strength += q.value, weight += c, x += c * (q.x || 0), y += c * (q.y || 0), z += c * (q.z || 0); + } + } + strength *= Math.sqrt(4 / numChildren); // scale accumulated strength according to number of dimensions + + treeNode.x = x / weight; + if (nDim > 1) { treeNode.y = y / weight; } + if (nDim > 2) { treeNode.z = z / weight; } + } + + // For leaf nodes, accumulate forces from coincident nodes. + else { + q = treeNode; + q.x = q.data.x; + if (nDim > 1) { q.y = q.data.y; } + if (nDim > 2) { q.z = q.data.z; } + do strength += strengths[q.data.index]; + while (q = q.next); + } + + treeNode.value = strength; + } + + function apply(treeNode, x1, arg1, arg2, arg3) { + if (!treeNode.value) return true; + var x2 = [arg1, arg2, arg3][nDim-1]; + + var x = treeNode.x - node.x, + y = (nDim > 1 ? treeNode.y - node.y : 0), + z = (nDim > 2 ? treeNode.z - node.z : 0), + w = x2 - x1, + l = x * x + y * y + z * z; + + // Apply the Barnes-Hut approximation if possible. + // Limit forces for very close nodes; randomize direction if coincident. + if (w * w / theta2 < l) { + if (l < distanceMax2) { + if (x === 0) x = jiggle(random), l += x * x; + if (nDim > 1 && y === 0) y = jiggle(random), l += y * y; + if (nDim > 2 && z === 0) z = jiggle(random), l += z * z; + if (l < distanceMin2) l = Math.sqrt(distanceMin2 * l); + node.vx += x * treeNode.value * alpha / l; + if (nDim > 1) { node.vy += y * treeNode.value * alpha / l; } + if (nDim > 2) { node.vz += z * treeNode.value * alpha / l; } + } + return true; + } + + // Otherwise, process points directly. + else if (treeNode.length || l >= distanceMax2) return; + + // Limit forces for very close nodes; randomize direction if coincident. + if (treeNode.data !== node || treeNode.next) { + if (x === 0) x = jiggle(random), l += x * x; + if (nDim > 1 && y === 0) y = jiggle(random), l += y * y; + if (nDim > 2 && z === 0) z = jiggle(random), l += z * z; + if (l < distanceMin2) l = Math.sqrt(distanceMin2 * l); + } + + do if (treeNode.data !== node) { + w = strengths[treeNode.data.index] * alpha / l; + node.vx += x * w; + if (nDim > 1) { node.vy += y * w; } + if (nDim > 2) { node.vz += z * w; } + } while (treeNode = treeNode.next); + } + + force.initialize = function(_nodes, ...args) { + nodes = _nodes; + random = args.find(arg => typeof arg === 'function') || Math.random; + nDim = args.find(arg => [1, 2, 3].includes(arg)) || 2; + initialize(); + }; + + force.strength = function(_) { + return arguments.length ? (strength = typeof _ === "function" ? _ : constant(+_), initialize(), force) : strength; + }; + + force.distanceMin = function(_) { + return arguments.length ? (distanceMin2 = _ * _, force) : Math.sqrt(distanceMin2); + }; + + force.distanceMax = function(_) { + return arguments.length ? (distanceMax2 = _ * _, force) : Math.sqrt(distanceMax2); + }; + + force.theta = function(_) { + return arguments.length ? (theta2 = _ * _, force) : Math.sqrt(theta2); + }; + + return force; + } + + function d3ForceRadial(radius, x, y, z) { + var nodes, + nDim, + strength = constant(0.1), + strengths, + radiuses; + + if (typeof radius !== "function") radius = constant(+radius); + if (x == null) x = 0; + if (y == null) y = 0; + if (z == null) z = 0; + + function force(alpha) { + for (var i = 0, n = nodes.length; i < n; ++i) { + var node = nodes[i], + dx = node.x - x || 1e-6, + dy = (node.y || 0) - y || 1e-6, + dz = (node.z || 0) - z || 1e-6, + r = Math.sqrt(dx * dx + dy * dy + dz * dz), + k = (radiuses[i] - r) * strengths[i] * alpha / r; + node.vx += dx * k; + if (nDim>1) { node.vy += dy * k; } + if (nDim>2) { node.vz += dz * k; } + } + } + + function initialize() { + if (!nodes) return; + var i, n = nodes.length; + strengths = new Array(n); + radiuses = new Array(n); + for (i = 0; i < n; ++i) { + radiuses[i] = +radius(nodes[i], i, nodes); + strengths[i] = isNaN(radiuses[i]) ? 0 : +strength(nodes[i], i, nodes); + } + } + + force.initialize = function(initNodes, ...args) { + nodes = initNodes; + nDim = args.find(arg => [1, 2, 3].includes(arg)) || 2; + initialize(); + }; + + force.strength = function(_) { + return arguments.length ? (strength = typeof _ === "function" ? _ : constant(+_), initialize(), force) : strength; + }; + + force.radius = function(_) { + return arguments.length ? (radius = typeof _ === "function" ? _ : constant(+_), initialize(), force) : radius; + }; + + force.x = function(_) { + return arguments.length ? (x = +_, force) : x; + }; + + force.y = function(_) { + return arguments.length ? (y = +_, force) : y; + }; + + force.z = function(_) { + return arguments.length ? (z = +_, force) : z; + }; + + return force; + } + + // math-inlining. + const { abs: abs$1, cos: cos$1, sin: sin$1, acos: acos$1, atan2, sqrt: sqrt$1, pow } = Math; + + // cube root function yielding real roots + function crt(v) { + return v < 0 ? -pow(-v, 1 / 3) : pow(v, 1 / 3); + } + + // trig constants + const pi$1 = Math.PI, + tau = 2 * pi$1, + quart = pi$1 / 2, + // float precision significant decimal + epsilon = 0.000001, + // extremas used in bbox calculation and similar algorithms + nMax = Number.MAX_SAFE_INTEGER || 9007199254740991, + nMin = Number.MIN_SAFE_INTEGER || -9007199254740991, + // a zero coordinate, which is surprisingly useful + ZERO = { x: 0, y: 0, z: 0 }; + + // Bezier utility functions + const utils = { + // Legendre-Gauss abscissae with n=24 (x_i values, defined at i=n as the roots of the nth order Legendre polynomial Pn(x)) + Tvalues: [ + -0.0640568928626056260850430826247450385909, + 0.0640568928626056260850430826247450385909, + -0.1911188674736163091586398207570696318404, + 0.1911188674736163091586398207570696318404, + -0.3150426796961633743867932913198102407864, + 0.3150426796961633743867932913198102407864, + -0.4337935076260451384870842319133497124524, + 0.4337935076260451384870842319133497124524, + -0.5454214713888395356583756172183723700107, + 0.5454214713888395356583756172183723700107, + -0.6480936519369755692524957869107476266696, + 0.6480936519369755692524957869107476266696, + -0.7401241915785543642438281030999784255232, + 0.7401241915785543642438281030999784255232, + -0.8200019859739029219539498726697452080761, + 0.8200019859739029219539498726697452080761, + -0.8864155270044010342131543419821967550873, + 0.8864155270044010342131543419821967550873, + -0.9382745520027327585236490017087214496548, + 0.9382745520027327585236490017087214496548, + -0.9747285559713094981983919930081690617411, + 0.9747285559713094981983919930081690617411, + -0.9951872199970213601799974097007368118745, + 0.9951872199970213601799974097007368118745, + ], + + // Legendre-Gauss weights with n=24 (w_i values, defined by a function linked to in the Bezier primer article) + Cvalues: [ + 0.1279381953467521569740561652246953718517, + 0.1279381953467521569740561652246953718517, + 0.1258374563468282961213753825111836887264, + 0.1258374563468282961213753825111836887264, + 0.121670472927803391204463153476262425607, + 0.121670472927803391204463153476262425607, + 0.1155056680537256013533444839067835598622, + 0.1155056680537256013533444839067835598622, + 0.1074442701159656347825773424466062227946, + 0.1074442701159656347825773424466062227946, + 0.0976186521041138882698806644642471544279, + 0.0976186521041138882698806644642471544279, + 0.086190161531953275917185202983742667185, + 0.086190161531953275917185202983742667185, + 0.0733464814110803057340336152531165181193, + 0.0733464814110803057340336152531165181193, + 0.0592985849154367807463677585001085845412, + 0.0592985849154367807463677585001085845412, + 0.0442774388174198061686027482113382288593, + 0.0442774388174198061686027482113382288593, + 0.0285313886289336631813078159518782864491, + 0.0285313886289336631813078159518782864491, + 0.0123412297999871995468056670700372915759, + 0.0123412297999871995468056670700372915759, + ], + + arcfn: function (t, derivativeFn) { + const d = derivativeFn(t); + let l = d.x * d.x + d.y * d.y; + if (typeof d.z !== "undefined") { + l += d.z * d.z; + } + return sqrt$1(l); + }, + + compute: function (t, points, _3d) { + // shortcuts + if (t === 0) { + points[0].t = 0; + return points[0]; + } + + const order = points.length - 1; + + if (t === 1) { + points[order].t = 1; + return points[order]; + } + + const mt = 1 - t; + let p = points; + + // constant? + if (order === 0) { + points[0].t = t; + return points[0]; + } + + // linear? + if (order === 1) { + const ret = { + x: mt * p[0].x + t * p[1].x, + y: mt * p[0].y + t * p[1].y, + t: t, + }; + if (_3d) { + ret.z = mt * p[0].z + t * p[1].z; + } + return ret; + } + + // quadratic/cubic curve? + if (order < 4) { + let mt2 = mt * mt, + t2 = t * t, + a, + b, + c, + d = 0; + if (order === 2) { + p = [p[0], p[1], p[2], ZERO]; + a = mt2; + b = mt * t * 2; + c = t2; + } else if (order === 3) { + a = mt2 * mt; + b = mt2 * t * 3; + c = mt * t2 * 3; + d = t * t2; + } + const ret = { + x: a * p[0].x + b * p[1].x + c * p[2].x + d * p[3].x, + y: a * p[0].y + b * p[1].y + c * p[2].y + d * p[3].y, + t: t, + }; + if (_3d) { + ret.z = a * p[0].z + b * p[1].z + c * p[2].z + d * p[3].z; + } + return ret; + } + + // higher order curves: use de Casteljau's computation + const dCpts = JSON.parse(JSON.stringify(points)); + while (dCpts.length > 1) { + for (let i = 0; i < dCpts.length - 1; i++) { + dCpts[i] = { + x: dCpts[i].x + (dCpts[i + 1].x - dCpts[i].x) * t, + y: dCpts[i].y + (dCpts[i + 1].y - dCpts[i].y) * t, + }; + if (typeof dCpts[i].z !== "undefined") { + dCpts[i].z = dCpts[i].z + (dCpts[i + 1].z - dCpts[i].z) * t; + } + } + dCpts.splice(dCpts.length - 1, 1); + } + dCpts[0].t = t; + return dCpts[0]; + }, + + computeWithRatios: function (t, points, ratios, _3d) { + const mt = 1 - t, + r = ratios, + p = points; + + let f1 = r[0], + f2 = r[1], + f3 = r[2], + f4 = r[3], + d; + + // spec for linear + f1 *= mt; + f2 *= t; + + if (p.length === 2) { + d = f1 + f2; + return { + x: (f1 * p[0].x + f2 * p[1].x) / d, + y: (f1 * p[0].y + f2 * p[1].y) / d, + z: !_3d ? false : (f1 * p[0].z + f2 * p[1].z) / d, + t: t, + }; + } + + // upgrade to quadratic + f1 *= mt; + f2 *= 2 * mt; + f3 *= t * t; + + if (p.length === 3) { + d = f1 + f2 + f3; + return { + x: (f1 * p[0].x + f2 * p[1].x + f3 * p[2].x) / d, + y: (f1 * p[0].y + f2 * p[1].y + f3 * p[2].y) / d, + z: !_3d ? false : (f1 * p[0].z + f2 * p[1].z + f3 * p[2].z) / d, + t: t, + }; + } + + // upgrade to cubic + f1 *= mt; + f2 *= 1.5 * mt; + f3 *= 3 * mt; + f4 *= t * t * t; + + if (p.length === 4) { + d = f1 + f2 + f3 + f4; + return { + x: (f1 * p[0].x + f2 * p[1].x + f3 * p[2].x + f4 * p[3].x) / d, + y: (f1 * p[0].y + f2 * p[1].y + f3 * p[2].y + f4 * p[3].y) / d, + z: !_3d + ? false + : (f1 * p[0].z + f2 * p[1].z + f3 * p[2].z + f4 * p[3].z) / d, + t: t, + }; + } + }, + + derive: function (points, _3d) { + const dpoints = []; + for (let p = points, d = p.length, c = d - 1; d > 1; d--, c--) { + const list = []; + for (let j = 0, dpt; j < c; j++) { + dpt = { + x: c * (p[j + 1].x - p[j].x), + y: c * (p[j + 1].y - p[j].y), + }; + if (_3d) { + dpt.z = c * (p[j + 1].z - p[j].z); + } + list.push(dpt); + } + dpoints.push(list); + p = list; + } + return dpoints; + }, + + between: function (v, m, M) { + return ( + (m <= v && v <= M) || + utils.approximately(v, m) || + utils.approximately(v, M) + ); + }, + + approximately: function (a, b, precision) { + return abs$1(a - b) <= (precision || epsilon); + }, + + length: function (derivativeFn) { + const z = 0.5, + len = utils.Tvalues.length; + + let sum = 0; + + for (let i = 0, t; i < len; i++) { + t = z * utils.Tvalues[i] + z; + sum += utils.Cvalues[i] * utils.arcfn(t, derivativeFn); + } + return z * sum; + }, + + map: function (v, ds, de, ts, te) { + const d1 = de - ds, + d2 = te - ts, + v2 = v - ds, + r = v2 / d1; + return ts + d2 * r; + }, + + lerp: function (r, v1, v2) { + const ret = { + x: v1.x + r * (v2.x - v1.x), + y: v1.y + r * (v2.y - v1.y), + }; + if (v1.z !== undefined && v2.z !== undefined) { + ret.z = v1.z + r * (v2.z - v1.z); + } + return ret; + }, + + pointToString: function (p) { + let s = p.x + "/" + p.y; + if (typeof p.z !== "undefined") { + s += "/" + p.z; + } + return s; + }, + + pointsToString: function (points) { + return "[" + points.map(utils.pointToString).join(", ") + "]"; + }, + + copy: function (obj) { + return JSON.parse(JSON.stringify(obj)); + }, + + angle: function (o, v1, v2) { + const dx1 = v1.x - o.x, + dy1 = v1.y - o.y, + dx2 = v2.x - o.x, + dy2 = v2.y - o.y, + cross = dx1 * dy2 - dy1 * dx2, + dot = dx1 * dx2 + dy1 * dy2; + return atan2(cross, dot); + }, + + // round as string, to avoid rounding errors + round: function (v, d) { + const s = "" + v; + const pos = s.indexOf("."); + return parseFloat(s.substring(0, pos + 1 + d)); + }, + + dist: function (p1, p2) { + const dx = p1.x - p2.x, + dy = p1.y - p2.y; + return sqrt$1(dx * dx + dy * dy); + }, + + closest: function (LUT, point) { + let mdist = pow(2, 63), + mpos, + d; + LUT.forEach(function (p, idx) { + d = utils.dist(point, p); + if (d < mdist) { + mdist = d; + mpos = idx; + } + }); + return { mdist: mdist, mpos: mpos }; + }, + + abcratio: function (t, n) { + // see ratio(t) note on http://pomax.github.io/bezierinfo/#abc + if (n !== 2 && n !== 3) { + return false; + } + if (typeof t === "undefined") { + t = 0.5; + } else if (t === 0 || t === 1) { + return t; + } + const bottom = pow(t, n) + pow(1 - t, n), + top = bottom - 1; + return abs$1(top / bottom); + }, + + projectionratio: function (t, n) { + // see u(t) note on http://pomax.github.io/bezierinfo/#abc + if (n !== 2 && n !== 3) { + return false; + } + if (typeof t === "undefined") { + t = 0.5; + } else if (t === 0 || t === 1) { + return t; + } + const top = pow(1 - t, n), + bottom = pow(t, n) + top; + return top / bottom; + }, + + lli8: function (x1, y1, x2, y2, x3, y3, x4, y4) { + const nx = + (x1 * y2 - y1 * x2) * (x3 - x4) - (x1 - x2) * (x3 * y4 - y3 * x4), + ny = (x1 * y2 - y1 * x2) * (y3 - y4) - (y1 - y2) * (x3 * y4 - y3 * x4), + d = (x1 - x2) * (y3 - y4) - (y1 - y2) * (x3 - x4); + if (d == 0) { + return false; + } + return { x: nx / d, y: ny / d }; + }, + + lli4: function (p1, p2, p3, p4) { + const x1 = p1.x, + y1 = p1.y, + x2 = p2.x, + y2 = p2.y, + x3 = p3.x, + y3 = p3.y, + x4 = p4.x, + y4 = p4.y; + return utils.lli8(x1, y1, x2, y2, x3, y3, x4, y4); + }, + + lli: function (v1, v2) { + return utils.lli4(v1, v1.c, v2, v2.c); + }, + + makeline: function (p1, p2) { + return new Bezier( + p1.x, + p1.y, + (p1.x + p2.x) / 2, + (p1.y + p2.y) / 2, + p2.x, + p2.y + ); + }, + + findbbox: function (sections) { + let mx = nMax, + my = nMax, + MX = nMin, + MY = nMin; + sections.forEach(function (s) { + const bbox = s.bbox(); + if (mx > bbox.x.min) mx = bbox.x.min; + if (my > bbox.y.min) my = bbox.y.min; + if (MX < bbox.x.max) MX = bbox.x.max; + if (MY < bbox.y.max) MY = bbox.y.max; + }); + return { + x: { min: mx, mid: (mx + MX) / 2, max: MX, size: MX - mx }, + y: { min: my, mid: (my + MY) / 2, max: MY, size: MY - my }, + }; + }, + + shapeintersections: function ( + s1, + bbox1, + s2, + bbox2, + curveIntersectionThreshold + ) { + if (!utils.bboxoverlap(bbox1, bbox2)) return []; + const intersections = []; + const a1 = [s1.startcap, s1.forward, s1.back, s1.endcap]; + const a2 = [s2.startcap, s2.forward, s2.back, s2.endcap]; + a1.forEach(function (l1) { + if (l1.virtual) return; + a2.forEach(function (l2) { + if (l2.virtual) return; + const iss = l1.intersects(l2, curveIntersectionThreshold); + if (iss.length > 0) { + iss.c1 = l1; + iss.c2 = l2; + iss.s1 = s1; + iss.s2 = s2; + intersections.push(iss); + } + }); + }); + return intersections; + }, + + makeshape: function (forward, back, curveIntersectionThreshold) { + const bpl = back.points.length; + const fpl = forward.points.length; + const start = utils.makeline(back.points[bpl - 1], forward.points[0]); + const end = utils.makeline(forward.points[fpl - 1], back.points[0]); + const shape = { + startcap: start, + forward: forward, + back: back, + endcap: end, + bbox: utils.findbbox([start, forward, back, end]), + }; + shape.intersections = function (s2) { + return utils.shapeintersections( + shape, + shape.bbox, + s2, + s2.bbox, + curveIntersectionThreshold + ); + }; + return shape; + }, + + getminmax: function (curve, d, list) { + if (!list) return { min: 0, max: 0 }; + let min = nMax, + max = nMin, + t, + c; + if (list.indexOf(0) === -1) { + list = [0].concat(list); + } + if (list.indexOf(1) === -1) { + list.push(1); + } + for (let i = 0, len = list.length; i < len; i++) { + t = list[i]; + c = curve.get(t); + if (c[d] < min) { + min = c[d]; + } + if (c[d] > max) { + max = c[d]; + } + } + return { min: min, mid: (min + max) / 2, max: max, size: max - min }; + }, + + align: function (points, line) { + const tx = line.p1.x, + ty = line.p1.y, + a = -atan2(line.p2.y - ty, line.p2.x - tx), + d = function (v) { + return { + x: (v.x - tx) * cos$1(a) - (v.y - ty) * sin$1(a), + y: (v.x - tx) * sin$1(a) + (v.y - ty) * cos$1(a), + }; + }; + return points.map(d); + }, + + roots: function (points, line) { + line = line || { p1: { x: 0, y: 0 }, p2: { x: 1, y: 0 } }; + + const order = points.length - 1; + const aligned = utils.align(points, line); + const reduce = function (t) { + return 0 <= t && t <= 1; + }; + + if (order === 2) { + const a = aligned[0].y, + b = aligned[1].y, + c = aligned[2].y, + d = a - 2 * b + c; + if (d !== 0) { + const m1 = -sqrt$1(b * b - a * c), + m2 = -a + b, + v1 = -(m1 + m2) / d, + v2 = -(-m1 + m2) / d; + return [v1, v2].filter(reduce); + } else if (b !== c && d === 0) { + return [(2 * b - c) / (2 * b - 2 * c)].filter(reduce); + } + return []; + } + + // see http://www.trans4mind.com/personal_development/mathematics/polynomials/cubicAlgebra.htm + const pa = aligned[0].y, + pb = aligned[1].y, + pc = aligned[2].y, + pd = aligned[3].y; + + let d = -pa + 3 * pb - 3 * pc + pd, + a = 3 * pa - 6 * pb + 3 * pc, + b = -3 * pa + 3 * pb, + c = pa; + + if (utils.approximately(d, 0)) { + // this is not a cubic curve. + if (utils.approximately(a, 0)) { + // in fact, this is not a quadratic curve either. + if (utils.approximately(b, 0)) { + // in fact in fact, there are no solutions. + return []; + } + // linear solution: + return [-c / b].filter(reduce); + } + // quadratic solution: + const q = sqrt$1(b * b - 4 * a * c), + a2 = 2 * a; + return [(q - b) / a2, (-b - q) / a2].filter(reduce); + } + + // at this point, we know we need a cubic solution: + + a /= d; + b /= d; + c /= d; + + const p = (3 * b - a * a) / 3, + p3 = p / 3, + q = (2 * a * a * a - 9 * a * b + 27 * c) / 27, + q2 = q / 2, + discriminant = q2 * q2 + p3 * p3 * p3; + + let u1, v1, x1, x2, x3; + if (discriminant < 0) { + const mp3 = -p / 3, + mp33 = mp3 * mp3 * mp3, + r = sqrt$1(mp33), + t = -q / (2 * r), + cosphi = t < -1 ? -1 : t > 1 ? 1 : t, + phi = acos$1(cosphi), + crtr = crt(r), + t1 = 2 * crtr; + x1 = t1 * cos$1(phi / 3) - a / 3; + x2 = t1 * cos$1((phi + tau) / 3) - a / 3; + x3 = t1 * cos$1((phi + 2 * tau) / 3) - a / 3; + return [x1, x2, x3].filter(reduce); + } else if (discriminant === 0) { + u1 = q2 < 0 ? crt(-q2) : -crt(q2); + x1 = 2 * u1 - a / 3; + x2 = -u1 - a / 3; + return [x1, x2].filter(reduce); + } else { + const sd = sqrt$1(discriminant); + u1 = crt(-q2 + sd); + v1 = crt(q2 + sd); + return [u1 - v1 - a / 3].filter(reduce); + } + }, + + droots: function (p) { + // quadratic roots are easy + if (p.length === 3) { + const a = p[0], + b = p[1], + c = p[2], + d = a - 2 * b + c; + if (d !== 0) { + const m1 = -sqrt$1(b * b - a * c), + m2 = -a + b, + v1 = -(m1 + m2) / d, + v2 = -(-m1 + m2) / d; + return [v1, v2]; + } else if (b !== c && d === 0) { + return [(2 * b - c) / (2 * (b - c))]; + } + return []; + } + + // linear roots are even easier + if (p.length === 2) { + const a = p[0], + b = p[1]; + if (a !== b) { + return [a / (a - b)]; + } + return []; + } + + return []; + }, + + curvature: function (t, d1, d2, _3d, kOnly) { + let num, + dnm, + adk, + dk, + k = 0, + r = 0; + + // + // We're using the following formula for curvature: + // + // x'y" - y'x" + // k(t) = ------------------ + // (x'² + y'²)^(3/2) + // + // from https://en.wikipedia.org/wiki/Radius_of_curvature#Definition + // + // With it corresponding 3D counterpart: + // + // sqrt( (y'z" - y"z')² + (z'x" - z"x')² + (x'y" - x"y')²) + // k(t) = ------------------------------------------------------- + // (x'² + y'² + z'²)^(3/2) + // + + const d = utils.compute(t, d1); + const dd = utils.compute(t, d2); + const qdsum = d.x * d.x + d.y * d.y; + + if (_3d) { + num = sqrt$1( + pow(d.y * dd.z - dd.y * d.z, 2) + + pow(d.z * dd.x - dd.z * d.x, 2) + + pow(d.x * dd.y - dd.x * d.y, 2) + ); + dnm = pow(qdsum + d.z * d.z, 3 / 2); + } else { + num = d.x * dd.y - d.y * dd.x; + dnm = pow(qdsum, 3 / 2); + } + + if (num === 0 || dnm === 0) { + return { k: 0, r: 0 }; + } + + k = num / dnm; + r = dnm / num; + + // We're also computing the derivative of kappa, because + // there is value in knowing the rate of change for the + // curvature along the curve. And we're just going to + // ballpark it based on an epsilon. + if (!kOnly) { + // compute k'(t) based on the interval before, and after it, + // to at least try to not introduce forward/backward pass bias. + const pk = utils.curvature(t - 0.001, d1, d2, _3d, true).k; + const nk = utils.curvature(t + 0.001, d1, d2, _3d, true).k; + dk = (nk - k + (k - pk)) / 2; + adk = (abs$1(nk - k) + abs$1(k - pk)) / 2; + } + + return { k: k, r: r, dk: dk, adk: adk }; + }, + + inflections: function (points) { + if (points.length < 4) return []; + + // FIXME: TODO: add in inflection abstraction for quartic+ curves? + + const p = utils.align(points, { p1: points[0], p2: points.slice(-1)[0] }), + a = p[2].x * p[1].y, + b = p[3].x * p[1].y, + c = p[1].x * p[2].y, + d = p[3].x * p[2].y, + v1 = 18 * (-3 * a + 2 * b + 3 * c - d), + v2 = 18 * (3 * a - b - 3 * c), + v3 = 18 * (c - a); + + if (utils.approximately(v1, 0)) { + if (!utils.approximately(v2, 0)) { + let t = -v3 / v2; + if (0 <= t && t <= 1) return [t]; + } + return []; + } + + const d2 = 2 * v1; + + if (utils.approximately(d2, 0)) return []; + + const trm = v2 * v2 - 4 * v1 * v3; + + if (trm < 0) return []; + + const sq = Math.sqrt(trm); + + return [(sq - v2) / d2, -(v2 + sq) / d2].filter(function (r) { + return 0 <= r && r <= 1; + }); + }, + + bboxoverlap: function (b1, b2) { + const dims = ["x", "y"], + len = dims.length; + + for (let i = 0, dim, l, t, d; i < len; i++) { + dim = dims[i]; + l = b1[dim].mid; + t = b2[dim].mid; + d = (b1[dim].size + b2[dim].size) / 2; + if (abs$1(l - t) >= d) return false; + } + return true; + }, + + expandbox: function (bbox, _bbox) { + if (_bbox.x.min < bbox.x.min) { + bbox.x.min = _bbox.x.min; + } + if (_bbox.y.min < bbox.y.min) { + bbox.y.min = _bbox.y.min; + } + if (_bbox.z && _bbox.z.min < bbox.z.min) { + bbox.z.min = _bbox.z.min; + } + if (_bbox.x.max > bbox.x.max) { + bbox.x.max = _bbox.x.max; + } + if (_bbox.y.max > bbox.y.max) { + bbox.y.max = _bbox.y.max; + } + if (_bbox.z && _bbox.z.max > bbox.z.max) { + bbox.z.max = _bbox.z.max; + } + bbox.x.mid = (bbox.x.min + bbox.x.max) / 2; + bbox.y.mid = (bbox.y.min + bbox.y.max) / 2; + if (bbox.z) { + bbox.z.mid = (bbox.z.min + bbox.z.max) / 2; + } + bbox.x.size = bbox.x.max - bbox.x.min; + bbox.y.size = bbox.y.max - bbox.y.min; + if (bbox.z) { + bbox.z.size = bbox.z.max - bbox.z.min; + } + }, + + pairiteration: function (c1, c2, curveIntersectionThreshold) { + const c1b = c1.bbox(), + c2b = c2.bbox(), + r = 100000, + threshold = curveIntersectionThreshold || 0.5; + + if ( + c1b.x.size + c1b.y.size < threshold && + c2b.x.size + c2b.y.size < threshold + ) { + return [ + (((r * (c1._t1 + c1._t2)) / 2) | 0) / r + + "/" + + (((r * (c2._t1 + c2._t2)) / 2) | 0) / r, + ]; + } + + let cc1 = c1.split(0.5), + cc2 = c2.split(0.5), + pairs = [ + { left: cc1.left, right: cc2.left }, + { left: cc1.left, right: cc2.right }, + { left: cc1.right, right: cc2.right }, + { left: cc1.right, right: cc2.left }, + ]; + + pairs = pairs.filter(function (pair) { + return utils.bboxoverlap(pair.left.bbox(), pair.right.bbox()); + }); + + let results = []; + + if (pairs.length === 0) return results; + + pairs.forEach(function (pair) { + results = results.concat( + utils.pairiteration(pair.left, pair.right, threshold) + ); + }); + + results = results.filter(function (v, i) { + return results.indexOf(v) === i; + }); + + return results; + }, + + getccenter: function (p1, p2, p3) { + const dx1 = p2.x - p1.x, + dy1 = p2.y - p1.y, + dx2 = p3.x - p2.x, + dy2 = p3.y - p2.y, + dx1p = dx1 * cos$1(quart) - dy1 * sin$1(quart), + dy1p = dx1 * sin$1(quart) + dy1 * cos$1(quart), + dx2p = dx2 * cos$1(quart) - dy2 * sin$1(quart), + dy2p = dx2 * sin$1(quart) + dy2 * cos$1(quart), + // chord midpoints + mx1 = (p1.x + p2.x) / 2, + my1 = (p1.y + p2.y) / 2, + mx2 = (p2.x + p3.x) / 2, + my2 = (p2.y + p3.y) / 2, + // midpoint offsets + mx1n = mx1 + dx1p, + my1n = my1 + dy1p, + mx2n = mx2 + dx2p, + my2n = my2 + dy2p, + // intersection of these lines: + arc = utils.lli8(mx1, my1, mx1n, my1n, mx2, my2, mx2n, my2n), + r = utils.dist(arc, p1); + + // arc start/end values, over mid point: + let s = atan2(p1.y - arc.y, p1.x - arc.x), + m = atan2(p2.y - arc.y, p2.x - arc.x), + e = atan2(p3.y - arc.y, p3.x - arc.x), + _; + + // determine arc direction (cw/ccw correction) + if (s < e) { + // if s m || m > e) { + s += tau; + } + if (s > e) { + _ = e; + e = s; + s = _; + } + } else { + // if e 4) { + if (arguments.length !== 1) { + throw new Error( + "Only new Bezier(point[]) is accepted for 4th and higher order curves" + ); + } + higher = true; + } + } else { + if (len !== 6 && len !== 8 && len !== 9 && len !== 12) { + if (arguments.length !== 1) { + throw new Error( + "Only new Bezier(point[]) is accepted for 4th and higher order curves" + ); + } + } + } + + const _3d = (this._3d = + (!higher && (len === 9 || len === 12)) || + (coords && coords[0] && typeof coords[0].z !== "undefined")); + + const points = (this.points = []); + for (let idx = 0, step = _3d ? 3 : 2; idx < len; idx += step) { + var point = { + x: args[idx], + y: args[idx + 1], + }; + if (_3d) { + point.z = args[idx + 2]; + } + points.push(point); + } + const order = (this.order = points.length - 1); + + const dims = (this.dims = ["x", "y"]); + if (_3d) dims.push("z"); + this.dimlen = dims.length; + + // is this curve, practically speaking, a straight line? + const aligned = utils.align(points, { p1: points[0], p2: points[order] }); + const baselength = utils.dist(points[0], points[order]); + this._linear = aligned.reduce((t, p) => t + abs(p.y), 0) < baselength / 50; + + this._lut = []; + this._t1 = 0; + this._t2 = 1; + this.update(); + } + + static quadraticFromPoints(p1, p2, p3, t) { + if (typeof t === "undefined") { + t = 0.5; + } + // shortcuts, although they're really dumb + if (t === 0) { + return new Bezier(p2, p2, p3); + } + if (t === 1) { + return new Bezier(p1, p2, p2); + } + // real fitting. + const abc = Bezier.getABC(2, p1, p2, p3, t); + return new Bezier(p1, abc.A, p3); + } + + static cubicFromPoints(S, B, E, t, d1) { + if (typeof t === "undefined") { + t = 0.5; + } + const abc = Bezier.getABC(3, S, B, E, t); + if (typeof d1 === "undefined") { + d1 = utils.dist(B, abc.C); + } + const d2 = (d1 * (1 - t)) / t; + + const selen = utils.dist(S, E), + lx = (E.x - S.x) / selen, + ly = (E.y - S.y) / selen, + bx1 = d1 * lx, + by1 = d1 * ly, + bx2 = d2 * lx, + by2 = d2 * ly; + // derivation of new hull coordinates + const e1 = { x: B.x - bx1, y: B.y - by1 }, + e2 = { x: B.x + bx2, y: B.y + by2 }, + A = abc.A, + v1 = { x: A.x + (e1.x - A.x) / (1 - t), y: A.y + (e1.y - A.y) / (1 - t) }, + v2 = { x: A.x + (e2.x - A.x) / t, y: A.y + (e2.y - A.y) / t }, + nc1 = { x: S.x + (v1.x - S.x) / t, y: S.y + (v1.y - S.y) / t }, + nc2 = { + x: E.x + (v2.x - E.x) / (1 - t), + y: E.y + (v2.y - E.y) / (1 - t), + }; + // ...done + return new Bezier(S, nc1, nc2, E); + } + + static getUtils() { + return utils; + } + + getUtils() { + return Bezier.getUtils(); + } + + static get PolyBezier() { + return PolyBezier; + } + + valueOf() { + return this.toString(); + } + + toString() { + return utils.pointsToString(this.points); + } + + toSVG() { + if (this._3d) return false; + const p = this.points, + x = p[0].x, + y = p[0].y, + s = ["M", x, y, this.order === 2 ? "Q" : "C"]; + for (let i = 1, last = p.length; i < last; i++) { + s.push(p[i].x); + s.push(p[i].y); + } + return s.join(" "); + } + + setRatios(ratios) { + if (ratios.length !== this.points.length) { + throw new Error("incorrect number of ratio values"); + } + this.ratios = ratios; + this._lut = []; // invalidate any precomputed LUT + } + + verify() { + const print = this.coordDigest(); + if (print !== this._print) { + this._print = print; + this.update(); + } + } + + coordDigest() { + return this.points + .map(function (c, pos) { + return "" + pos + c.x + c.y + (c.z ? c.z : 0); + }) + .join(""); + } + + update() { + // invalidate any precomputed LUT + this._lut = []; + this.dpoints = utils.derive(this.points, this._3d); + this.computedirection(); + } + + computedirection() { + const points = this.points; + const angle = utils.angle(points[0], points[this.order], points[1]); + this.clockwise = angle > 0; + } + + length() { + return utils.length(this.derivative.bind(this)); + } + + static getABC(order = 2, S, B, E, t = 0.5) { + const u = utils.projectionratio(t, order), + um = 1 - u, + C = { + x: u * S.x + um * E.x, + y: u * S.y + um * E.y, + }, + s = utils.abcratio(t, order), + A = { + x: B.x + (B.x - C.x) / s, + y: B.y + (B.y - C.y) / s, + }; + return { A, B, C, S, E }; + } + + getABC(t, B) { + B = B || this.get(t); + let S = this.points[0]; + let E = this.points[this.order]; + return Bezier.getABC(this.order, S, B, E, t); + } + + getLUT(steps) { + this.verify(); + steps = steps || 100; + if (this._lut.length === steps + 1) { + return this._lut; + } + this._lut = []; + // n steps means n+1 points + steps++; + this._lut = []; + for (let i = 0, p, t; i < steps; i++) { + t = i / (steps - 1); + p = this.compute(t); + p.t = t; + this._lut.push(p); + } + return this._lut; + } + + on(point, error) { + error = error || 5; + const lut = this.getLUT(), + hits = []; + for (let i = 0, c, t = 0; i < lut.length; i++) { + c = lut[i]; + if (utils.dist(c, point) < error) { + hits.push(c); + t += i / lut.length; + } + } + if (!hits.length) return false; + return (t /= hits.length); + } + + project(point) { + // step 1: coarse check + const LUT = this.getLUT(), + l = LUT.length - 1, + closest = utils.closest(LUT, point), + mpos = closest.mpos, + t1 = (mpos - 1) / l, + t2 = (mpos + 1) / l, + step = 0.1 / l; + + // step 2: fine check + let mdist = closest.mdist, + t = t1, + ft = t, + p; + mdist += 1; + for (let d; t < t2 + step; t += step) { + p = this.compute(t); + d = utils.dist(point, p); + if (d < mdist) { + mdist = d; + ft = t; + } + } + ft = ft < 0 ? 0 : ft > 1 ? 1 : ft; + p = this.compute(ft); + p.t = ft; + p.d = mdist; + return p; + } + + get(t) { + return this.compute(t); + } + + point(idx) { + return this.points[idx]; + } + + compute(t) { + if (this.ratios) { + return utils.computeWithRatios(t, this.points, this.ratios, this._3d); + } + return utils.compute(t, this.points, this._3d, this.ratios); + } + + raise() { + const p = this.points, + np = [p[0]], + k = p.length; + for (let i = 1, pi, pim; i < k; i++) { + pi = p[i]; + pim = p[i - 1]; + np[i] = { + x: ((k - i) / k) * pi.x + (i / k) * pim.x, + y: ((k - i) / k) * pi.y + (i / k) * pim.y, + }; + } + np[k] = p[k - 1]; + return new Bezier(np); + } + + derivative(t) { + return utils.compute(t, this.dpoints[0], this._3d); + } + + dderivative(t) { + return utils.compute(t, this.dpoints[1], this._3d); + } + + align() { + let p = this.points; + return new Bezier(utils.align(p, { p1: p[0], p2: p[p.length - 1] })); + } + + curvature(t) { + return utils.curvature(t, this.dpoints[0], this.dpoints[1], this._3d); + } + + inflections() { + return utils.inflections(this.points); + } + + normal(t) { + return this._3d ? this.__normal3(t) : this.__normal2(t); + } + + __normal2(t) { + const d = this.derivative(t); + const q = sqrt(d.x * d.x + d.y * d.y); + return { t, x: -d.y / q, y: d.x / q }; + } + + __normal3(t) { + // see http://stackoverflow.com/questions/25453159 + const r1 = this.derivative(t), + r2 = this.derivative(t + 0.01), + q1 = sqrt(r1.x * r1.x + r1.y * r1.y + r1.z * r1.z), + q2 = sqrt(r2.x * r2.x + r2.y * r2.y + r2.z * r2.z); + r1.x /= q1; + r1.y /= q1; + r1.z /= q1; + r2.x /= q2; + r2.y /= q2; + r2.z /= q2; + // cross product + const c = { + x: r2.y * r1.z - r2.z * r1.y, + y: r2.z * r1.x - r2.x * r1.z, + z: r2.x * r1.y - r2.y * r1.x, + }; + const m = sqrt(c.x * c.x + c.y * c.y + c.z * c.z); + c.x /= m; + c.y /= m; + c.z /= m; + // rotation matrix + const R = [ + c.x * c.x, + c.x * c.y - c.z, + c.x * c.z + c.y, + c.x * c.y + c.z, + c.y * c.y, + c.y * c.z - c.x, + c.x * c.z - c.y, + c.y * c.z + c.x, + c.z * c.z, + ]; + // normal vector: + const n = { + t, + x: R[0] * r1.x + R[1] * r1.y + R[2] * r1.z, + y: R[3] * r1.x + R[4] * r1.y + R[5] * r1.z, + z: R[6] * r1.x + R[7] * r1.y + R[8] * r1.z, + }; + return n; + } + + hull(t) { + let p = this.points, + _p = [], + q = [], + idx = 0; + q[idx++] = p[0]; + q[idx++] = p[1]; + q[idx++] = p[2]; + if (this.order === 3) { + q[idx++] = p[3]; + } + // we lerp between all points at each iteration, until we have 1 point left. + while (p.length > 1) { + _p = []; + for (let i = 0, pt, l = p.length - 1; i < l; i++) { + pt = utils.lerp(t, p[i], p[i + 1]); + q[idx++] = pt; + _p.push(pt); + } + p = _p; + } + return q; + } + + split(t1, t2) { + // shortcuts + if (t1 === 0 && !!t2) { + return this.split(t2).left; + } + if (t2 === 1) { + return this.split(t1).right; + } + + // no shortcut: use "de Casteljau" iteration. + const q = this.hull(t1); + const result = { + left: + this.order === 2 + ? new Bezier([q[0], q[3], q[5]]) + : new Bezier([q[0], q[4], q[7], q[9]]), + right: + this.order === 2 + ? new Bezier([q[5], q[4], q[2]]) + : new Bezier([q[9], q[8], q[6], q[3]]), + span: q, + }; + + // make sure we bind _t1/_t2 information! + result.left._t1 = utils.map(0, 0, 1, this._t1, this._t2); + result.left._t2 = utils.map(t1, 0, 1, this._t1, this._t2); + result.right._t1 = utils.map(t1, 0, 1, this._t1, this._t2); + result.right._t2 = utils.map(1, 0, 1, this._t1, this._t2); + + // if we have no t2, we're done + if (!t2) { + return result; + } + + // if we have a t2, split again: + t2 = utils.map(t2, t1, 1, 0, 1); + return result.right.split(t2).left; + } + + extrema() { + const result = {}; + let roots = []; + + this.dims.forEach( + function (dim) { + let mfn = function (v) { + return v[dim]; + }; + let p = this.dpoints[0].map(mfn); + result[dim] = utils.droots(p); + if (this.order === 3) { + p = this.dpoints[1].map(mfn); + result[dim] = result[dim].concat(utils.droots(p)); + } + result[dim] = result[dim].filter(function (t) { + return t >= 0 && t <= 1; + }); + roots = roots.concat(result[dim].sort(utils.numberSort)); + }.bind(this) + ); + + result.values = roots.sort(utils.numberSort).filter(function (v, idx) { + return roots.indexOf(v) === idx; + }); + + return result; + } + + bbox() { + const extrema = this.extrema(), + result = {}; + this.dims.forEach( + function (d) { + result[d] = utils.getminmax(this, d, extrema[d]); + }.bind(this) + ); + return result; + } + + overlaps(curve) { + const lbbox = this.bbox(), + tbbox = curve.bbox(); + return utils.bboxoverlap(lbbox, tbbox); + } + + offset(t, d) { + if (typeof d !== "undefined") { + const c = this.get(t), + n = this.normal(t); + const ret = { + c: c, + n: n, + x: c.x + n.x * d, + y: c.y + n.y * d, + }; + if (this._3d) { + ret.z = c.z + n.z * d; + } + return ret; + } + if (this._linear) { + const nv = this.normal(0), + coords = this.points.map(function (p) { + const ret = { + x: p.x + t * nv.x, + y: p.y + t * nv.y, + }; + if (p.z && nv.z) { + ret.z = p.z + t * nv.z; + } + return ret; + }); + return [new Bezier(coords)]; + } + return this.reduce().map(function (s) { + if (s._linear) { + return s.offset(t)[0]; + } + return s.scale(t); + }); + } + + simple() { + if (this.order === 3) { + const a1 = utils.angle(this.points[0], this.points[3], this.points[1]); + const a2 = utils.angle(this.points[0], this.points[3], this.points[2]); + if ((a1 > 0 && a2 < 0) || (a1 < 0 && a2 > 0)) return false; + } + const n1 = this.normal(0); + const n2 = this.normal(1); + let s = n1.x * n2.x + n1.y * n2.y; + if (this._3d) { + s += n1.z * n2.z; + } + return abs(acos(s)) < pi / 3; + } + + reduce() { + // TODO: examine these var types in more detail... + let i, + t1 = 0, + t2 = 0, + step = 0.01, + segment, + pass1 = [], + pass2 = []; + // first pass: split on extrema + let extrema = this.extrema().values; + if (extrema.indexOf(0) === -1) { + extrema = [0].concat(extrema); + } + if (extrema.indexOf(1) === -1) { + extrema.push(1); + } + + for (t1 = extrema[0], i = 1; i < extrema.length; i++) { + t2 = extrema[i]; + segment = this.split(t1, t2); + segment._t1 = t1; + segment._t2 = t2; + pass1.push(segment); + t1 = t2; + } + + // second pass: further reduce these segments to simple segments + pass1.forEach(function (p1) { + t1 = 0; + t2 = 0; + while (t2 <= 1) { + for (t2 = t1 + step; t2 <= 1 + step; t2 += step) { + segment = p1.split(t1, t2); + if (!segment.simple()) { + t2 -= step; + if (abs(t1 - t2) < step) { + // we can never form a reduction + return []; + } + segment = p1.split(t1, t2); + segment._t1 = utils.map(t1, 0, 1, p1._t1, p1._t2); + segment._t2 = utils.map(t2, 0, 1, p1._t1, p1._t2); + pass2.push(segment); + t1 = t2; + break; + } + } + } + if (t1 < 1) { + segment = p1.split(t1, 1); + segment._t1 = utils.map(t1, 0, 1, p1._t1, p1._t2); + segment._t2 = p1._t2; + pass2.push(segment); + } + }); + return pass2; + } + + translate(v, d1, d2) { + d2 = typeof d2 === "number" ? d2 : d1; + + // TODO: make this take curves with control points outside + // of the start-end interval into account + + const o = this.order; + let d = this.points.map((_, i) => (1 - i / o) * d1 + (i / o) * d2); + return new Bezier( + this.points.map((p, i) => ({ + x: p.x + v.x * d[i], + y: p.y + v.y * d[i], + })) + ); + } + + scale(d) { + const order = this.order; + let distanceFn = false; + if (typeof d === "function") { + distanceFn = d; + } + if (distanceFn && order === 2) { + return this.raise().scale(distanceFn); + } + + // TODO: add special handling for non-linear degenerate curves. + + const clockwise = this.clockwise; + const points = this.points; + + if (this._linear) { + return this.translate( + this.normal(0), + distanceFn ? distanceFn(0) : d, + distanceFn ? distanceFn(1) : d + ); + } + + const r1 = distanceFn ? distanceFn(0) : d; + const r2 = distanceFn ? distanceFn(1) : d; + const v = [this.offset(0, 10), this.offset(1, 10)]; + const np = []; + const o = utils.lli4(v[0], v[0].c, v[1], v[1].c); + + if (!o) { + throw new Error("cannot scale this curve. Try reducing it first."); + } + + // move all points by distance 'd' wrt the origin 'o', + // and move end points by fixed distance along normal. + [0, 1].forEach(function (t) { + const p = (np[t * order] = utils.copy(points[t * order])); + p.x += (t ? r2 : r1) * v[t].n.x; + p.y += (t ? r2 : r1) * v[t].n.y; + }); + + if (!distanceFn) { + // move control points to lie on the intersection of the offset + // derivative vector, and the origin-through-control vector + [0, 1].forEach((t) => { + if (order === 2 && !!t) return; + const p = np[t * order]; + const d = this.derivative(t); + const p2 = { x: p.x + d.x, y: p.y + d.y }; + np[t + 1] = utils.lli4(p, p2, o, points[t + 1]); + }); + return new Bezier(np); + } + + // move control points by "however much necessary to + // ensure the correct tangent to endpoint". + [0, 1].forEach(function (t) { + if (order === 2 && !!t) return; + var p = points[t + 1]; + var ov = { + x: p.x - o.x, + y: p.y - o.y, + }; + var rc = distanceFn ? distanceFn((t + 1) / order) : d; + if (distanceFn && !clockwise) rc = -rc; + var m = sqrt(ov.x * ov.x + ov.y * ov.y); + ov.x /= m; + ov.y /= m; + np[t + 1] = { + x: p.x + rc * ov.x, + y: p.y + rc * ov.y, + }; + }); + return new Bezier(np); + } + + outline(d1, d2, d3, d4) { + d2 = d2 === undefined ? d1 : d2; + + if (this._linear) { + // TODO: find the actual extrema, because they might + // be before the start, or past the end. + + const n = this.normal(0); + const start = this.points[0]; + const end = this.points[this.points.length - 1]; + let s, mid, e; + + if (d3 === undefined) { + d3 = d1; + d4 = d2; + } + + s = { x: start.x + n.x * d1, y: start.y + n.y * d1 }; + e = { x: end.x + n.x * d3, y: end.y + n.y * d3 }; + mid = { x: (s.x + e.x) / 2, y: (s.y + e.y) / 2 }; + const fline = [s, mid, e]; + + s = { x: start.x - n.x * d2, y: start.y - n.y * d2 }; + e = { x: end.x - n.x * d4, y: end.y - n.y * d4 }; + mid = { x: (s.x + e.x) / 2, y: (s.y + e.y) / 2 }; + const bline = [e, mid, s]; + + const ls = utils.makeline(bline[2], fline[0]); + const le = utils.makeline(fline[2], bline[0]); + const segments = [ls, new Bezier(fline), le, new Bezier(bline)]; + return new PolyBezier(segments); + } + + const reduced = this.reduce(), + len = reduced.length, + fcurves = []; + + let bcurves = [], + p, + alen = 0, + tlen = this.length(); + + const graduated = typeof d3 !== "undefined" && typeof d4 !== "undefined"; + + function linearDistanceFunction(s, e, tlen, alen, slen) { + return function (v) { + const f1 = alen / tlen, + f2 = (alen + slen) / tlen, + d = e - s; + return utils.map(v, 0, 1, s + f1 * d, s + f2 * d); + }; + } + + // form curve oulines + reduced.forEach(function (segment) { + const slen = segment.length(); + if (graduated) { + fcurves.push( + segment.scale(linearDistanceFunction(d1, d3, tlen, alen, slen)) + ); + bcurves.push( + segment.scale(linearDistanceFunction(-d2, -d4, tlen, alen, slen)) + ); + } else { + fcurves.push(segment.scale(d1)); + bcurves.push(segment.scale(-d2)); + } + alen += slen; + }); + + // reverse the "return" outline + bcurves = bcurves + .map(function (s) { + p = s.points; + if (p[3]) { + s.points = [p[3], p[2], p[1], p[0]]; + } else { + s.points = [p[2], p[1], p[0]]; + } + return s; + }) + .reverse(); + + // form the endcaps as lines + const fs = fcurves[0].points[0], + fe = fcurves[len - 1].points[fcurves[len - 1].points.length - 1], + bs = bcurves[len - 1].points[bcurves[len - 1].points.length - 1], + be = bcurves[0].points[0], + ls = utils.makeline(bs, fs), + le = utils.makeline(fe, be), + segments = [ls].concat(fcurves).concat([le]).concat(bcurves); + + return new PolyBezier(segments); + } + + outlineshapes(d1, d2, curveIntersectionThreshold) { + d2 = d2 || d1; + const outline = this.outline(d1, d2).curves; + const shapes = []; + for (let i = 1, len = outline.length; i < len / 2; i++) { + const shape = utils.makeshape( + outline[i], + outline[len - i], + curveIntersectionThreshold + ); + shape.startcap.virtual = i > 1; + shape.endcap.virtual = i < len / 2 - 1; + shapes.push(shape); + } + return shapes; + } + + intersects(curve, curveIntersectionThreshold) { + if (!curve) return this.selfintersects(curveIntersectionThreshold); + if (curve.p1 && curve.p2) { + return this.lineIntersects(curve); + } + if (curve instanceof Bezier) { + curve = curve.reduce(); + } + return this.curveintersects( + this.reduce(), + curve, + curveIntersectionThreshold + ); + } + + lineIntersects(line) { + const mx = min(line.p1.x, line.p2.x), + my = min(line.p1.y, line.p2.y), + MX = max(line.p1.x, line.p2.x), + MY = max(line.p1.y, line.p2.y); + return utils.roots(this.points, line).filter((t) => { + var p = this.get(t); + return utils.between(p.x, mx, MX) && utils.between(p.y, my, MY); + }); + } + + selfintersects(curveIntersectionThreshold) { + // "simple" curves cannot intersect with their direct + // neighbour, so for each segment X we check whether + // it intersects [0:x-2][x+2:last]. + + const reduced = this.reduce(), + len = reduced.length - 2, + results = []; + + for (let i = 0, result, left, right; i < len; i++) { + left = reduced.slice(i, i + 1); + right = reduced.slice(i + 2); + result = this.curveintersects(left, right, curveIntersectionThreshold); + results.push(...result); + } + return results; + } + + curveintersects(c1, c2, curveIntersectionThreshold) { + const pairs = []; + // step 1: pair off any overlapping segments + c1.forEach(function (l) { + c2.forEach(function (r) { + if (l.overlaps(r)) { + pairs.push({ left: l, right: r }); + } + }); + }); + // step 2: for each pairing, run through the convergence algorithm. + let intersections = []; + pairs.forEach(function (pair) { + const result = utils.pairiteration( + pair.left, + pair.right, + curveIntersectionThreshold + ); + if (result.length > 0) { + intersections = intersections.concat(result); + } + }); + return intersections; + } + + arcs(errorThreshold) { + errorThreshold = errorThreshold || 0.5; + return this._iterate(errorThreshold, []); + } + + _error(pc, np1, s, e) { + const q = (e - s) / 4, + c1 = this.get(s + q), + c2 = this.get(e - q), + ref = utils.dist(pc, np1), + d1 = utils.dist(pc, c1), + d2 = utils.dist(pc, c2); + return abs(d1 - ref) + abs(d2 - ref); + } + + _iterate(errorThreshold, circles) { + let t_s = 0, + t_e = 1, + safety; + // we do a binary search to find the "good `t` closest to no-longer-good" + do { + safety = 0; + + // step 1: start with the maximum possible arc + t_e = 1; + + // points: + let np1 = this.get(t_s), + np2, + np3, + arc, + prev_arc; + + // booleans: + let curr_good = false, + prev_good = false, + done; + + // numbers: + let t_m = t_e, + prev_e = 1; + + // step 2: find the best possible arc + do { + prev_good = curr_good; + prev_arc = arc; + t_m = (t_s + t_e) / 2; + + np2 = this.get(t_m); + np3 = this.get(t_e); + + arc = utils.getccenter(np1, np2, np3); + + //also save the t values + arc.interval = { + start: t_s, + end: t_e, + }; + + let error = this._error(arc, np1, t_s, t_e); + curr_good = error <= errorThreshold; + + done = prev_good && !curr_good; + if (!done) prev_e = t_e; + + // this arc is fine: we can move 'e' up to see if we can find a wider arc + if (curr_good) { + // if e is already at max, then we're done for this arc. + if (t_e >= 1) { + // make sure we cap at t=1 + arc.interval.end = prev_e = 1; + prev_arc = arc; + // if we capped the arc segment to t=1 we also need to make sure that + // the arc's end angle is correct with respect to the bezier end point. + if (t_e > 1) { + let d = { + x: arc.x + arc.r * cos(arc.e), + y: arc.y + arc.r * sin(arc.e), + }; + arc.e += utils.angle({ x: arc.x, y: arc.y }, d, this.get(1)); + } + break; + } + // if not, move it up by half the iteration distance + t_e = t_e + (t_e - t_s) / 2; + } else { + // this is a bad arc: we need to move 'e' down to find a good arc + t_e = t_m; + } + } while (!done && safety++ < 100); + + if (safety >= 100) { + break; + } + + // console.log("L835: [F] arc found", t_s, prev_e, prev_arc.x, prev_arc.y, prev_arc.s, prev_arc.e); + + prev_arc = prev_arc ? prev_arc : arc; + circles.push(prev_arc); + t_s = prev_e; + } while (t_e < 1); + return circles; + } + } + + function _iterableToArrayLimit(arr, i) { + var _i = null == arr ? null : "undefined" != typeof Symbol && arr[Symbol.iterator] || arr["@@iterator"]; + if (null != _i) { + var _s, + _e, + _x, + _r, + _arr = [], + _n = !0, + _d = !1; + try { + if (_x = (_i = _i.call(arr)).next, 0 === i) { + if (Object(_i) !== _i) return; + _n = !1; + } else for (; !(_n = (_s = _x.call(_i)).done) && (_arr.push(_s.value), _arr.length !== i); _n = !0); + } catch (err) { + _d = !0, _e = err; + } finally { + try { + if (!_n && null != _i.return && (_r = _i.return(), Object(_r) !== _r)) return; + } finally { + if (_d) throw _e; + } + } + return _arr; + } + } + function _objectWithoutPropertiesLoose(source, excluded) { + if (source == null) return {}; + var target = {}; + var sourceKeys = Object.keys(source); + var key, i; + for (i = 0; i < sourceKeys.length; i++) { + key = sourceKeys[i]; + if (excluded.indexOf(key) >= 0) continue; + target[key] = source[key]; + } + return target; + } + function _objectWithoutProperties(source, excluded) { + if (source == null) return {}; + var target = _objectWithoutPropertiesLoose(source, excluded); + var key, i; + if (Object.getOwnPropertySymbols) { + var sourceSymbolKeys = Object.getOwnPropertySymbols(source); + for (i = 0; i < sourceSymbolKeys.length; i++) { + key = sourceSymbolKeys[i]; + if (excluded.indexOf(key) >= 0) continue; + if (!Object.prototype.propertyIsEnumerable.call(source, key)) continue; + target[key] = source[key]; + } + } + return target; + } + function _slicedToArray(arr, i) { + return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _unsupportedIterableToArray(arr, i) || _nonIterableRest(); + } + function _toConsumableArray(arr) { + return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _unsupportedIterableToArray(arr) || _nonIterableSpread(); + } + function _arrayWithoutHoles(arr) { + if (Array.isArray(arr)) return _arrayLikeToArray(arr); + } + function _arrayWithHoles(arr) { + if (Array.isArray(arr)) return arr; + } + function _iterableToArray(iter) { + if (typeof Symbol !== "undefined" && iter[Symbol.iterator] != null || iter["@@iterator"] != null) return Array.from(iter); + } + function _unsupportedIterableToArray(o, minLen) { + if (!o) return; + if (typeof o === "string") return _arrayLikeToArray(o, minLen); + var n = Object.prototype.toString.call(o).slice(8, -1); + if (n === "Object" && o.constructor) n = o.constructor.name; + if (n === "Map" || n === "Set") return Array.from(o); + if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); + } + function _arrayLikeToArray(arr, len) { + if (len == null || len > arr.length) len = arr.length; + for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i]; + return arr2; + } + function _nonIterableSpread() { + throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); + } + function _nonIterableRest() { + throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); + } + function _toPrimitive(input, hint) { + if (typeof input !== "object" || input === null) return input; + var prim = input[Symbol.toPrimitive]; + if (prim !== undefined) { + var res = prim.call(input, hint || "default"); + if (typeof res !== "object") return res; + throw new TypeError("@@toPrimitive must return a primitive value."); + } + return (hint === "string" ? String : Number)(input); + } + function _toPropertyKey(arg) { + var key = _toPrimitive(arg, "string"); + return typeof key === "symbol" ? key : String(key); + } + + var index = (function () { + var list = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : []; + var keyAccessors = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : []; + var multiItem = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : true; + var flattenKeys = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : false; + var keys = (keyAccessors instanceof Array ? keyAccessors.length ? keyAccessors : [undefined] : [keyAccessors]).map(function (key) { + return { + keyAccessor: key, + isProp: !(key instanceof Function) + }; + }); + var indexedResult = list.reduce(function (res, item) { + var iterObj = res; + var itemVal = item; + keys.forEach(function (_ref, idx) { + var keyAccessor = _ref.keyAccessor, + isProp = _ref.isProp; + var key; + if (isProp) { + var _itemVal = itemVal, + propVal = _itemVal[keyAccessor], + rest = _objectWithoutProperties(_itemVal, [keyAccessor].map(_toPropertyKey)); + key = propVal; + itemVal = rest; + } else { + key = keyAccessor(itemVal, idx); + } + if (idx + 1 < keys.length) { + if (!iterObj.hasOwnProperty(key)) { + iterObj[key] = {}; + } + iterObj = iterObj[key]; + } else { + // Leaf key + if (multiItem) { + if (!iterObj.hasOwnProperty(key)) { + iterObj[key] = []; + } + iterObj[key].push(itemVal); + } else { + iterObj[key] = itemVal; + } + } + }); + return res; + }, {}); + if (multiItem instanceof Function) { + // Reduce leaf multiple values + (function reduce(node) { + var level = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 1; + if (level === keys.length) { + Object.keys(node).forEach(function (k) { + return node[k] = multiItem(node[k]); + }); + } else { + Object.values(node).forEach(function (child) { + return reduce(child, level + 1); + }); + } + })(indexedResult); // IIFE + } + + var result = indexedResult; + if (flattenKeys) { + // flatten into array + result = []; + (function flatten(node) { + var accKeys = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : []; + if (accKeys.length === keys.length) { + result.push({ + keys: accKeys, + vals: node + }); + } else { + Object.entries(node).forEach(function (_ref2) { + var _ref3 = _slicedToArray(_ref2, 2), + key = _ref3[0], + val = _ref3[1]; + return flatten(val, [].concat(_toConsumableArray(accKeys), [key])); + }); + } + })(indexedResult); //IIFE + + if (keyAccessors instanceof Array && keyAccessors.length === 0 && result.length === 1) { + // clear keys if there's no key accessors (single result) + result[0].keys = []; + } + } + return result; + }); + + function initRange(domain, range) { + switch (arguments.length) { + case 0: break; + case 1: this.range(domain); break; + default: this.range(range).domain(domain); break; + } + return this; + } + + const implicit = Symbol("implicit"); + + function ordinal() { + var index = new InternMap(), + domain = [], + range = [], + unknown = implicit; + + function scale(d) { + let i = index.get(d); + if (i === undefined) { + if (unknown !== implicit) return unknown; + index.set(d, i = domain.push(d) - 1); + } + return range[i % range.length]; + } + + scale.domain = function(_) { + if (!arguments.length) return domain.slice(); + domain = [], index = new InternMap(); + for (const value of _) { + if (index.has(value)) continue; + index.set(value, domain.push(value) - 1); + } + return scale; + }; + + scale.range = function(_) { + return arguments.length ? (range = Array.from(_), scale) : range.slice(); + }; + + scale.unknown = function(_) { + return arguments.length ? (unknown = _, scale) : unknown; + }; + + scale.copy = function() { + return ordinal(domain, range).unknown(unknown); + }; + + initRange.apply(scale, arguments); + + return scale; + } + + function colors(specifier) { + var n = specifier.length / 6 | 0, colors = new Array(n), i = 0; + while (i < n) colors[i] = "#" + specifier.slice(i * 6, ++i * 6); + return colors; + } + + var schemePaired = colors("a6cee31f78b4b2df8a33a02cfb9a99e31a1cfdbf6fff7f00cab2d66a3d9affff99b15928"); + + var autoColorScale = ordinal(schemePaired); + + // Autoset attribute colorField by colorByAccessor property + // If an object has already a color, don't set it + // Objects can be nodes or links + function autoColorObjects(objects, colorByAccessor, colorField) { + if (!colorByAccessor || typeof colorField !== 'string') return; + objects.filter(function (obj) { + return !obj[colorField]; + }).forEach(function (obj) { + obj[colorField] = autoColorScale(colorByAccessor(obj)); + }); + } + + function getDagDepths (_ref, idAccessor) { + var nodes = _ref.nodes, + links = _ref.links; + var _ref2 = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {}, + _ref2$nodeFilter = _ref2.nodeFilter, + nodeFilter = _ref2$nodeFilter === void 0 ? function () { + return true; + } : _ref2$nodeFilter, + _ref2$onLoopError = _ref2.onLoopError, + onLoopError = _ref2$onLoopError === void 0 ? function (loopIds) { + throw "Invalid DAG structure! Found cycle in node path: ".concat(loopIds.join(' -> '), "."); + } : _ref2$onLoopError; + // linked graph + var graph = {}; + nodes.forEach(function (node) { + return graph[idAccessor(node)] = { + data: node, + out: [], + depth: -1, + skip: !nodeFilter(node) + }; + }); + links.forEach(function (_ref3) { + var source = _ref3.source, + target = _ref3.target; + var sourceId = getNodeId(source); + var targetId = getNodeId(target); + if (!graph.hasOwnProperty(sourceId)) throw "Missing source node with id: ".concat(sourceId); + if (!graph.hasOwnProperty(targetId)) throw "Missing target node with id: ".concat(targetId); + var sourceNode = graph[sourceId]; + var targetNode = graph[targetId]; + sourceNode.out.push(targetNode); + function getNodeId(node) { + return _typeof$1(node) === 'object' ? idAccessor(node) : node; + } + }); + var foundLoops = []; + traverse(Object.values(graph)); + var nodeDepths = Object.assign.apply(Object, [{}].concat(_toConsumableArray$2(Object.entries(graph).filter(function (_ref4) { + var _ref5 = _slicedToArray$2(_ref4, 2), + node = _ref5[1]; + return !node.skip; + }).map(function (_ref6) { + var _ref7 = _slicedToArray$2(_ref6, 2), + id = _ref7[0], + node = _ref7[1]; + return _defineProperty({}, id, node.depth); + })))); + return nodeDepths; + function traverse(nodes) { + var nodeStack = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : []; + var currentDepth = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 0; + var _loop = function _loop() { + var node = nodes[i]; + if (nodeStack.indexOf(node) !== -1) { + var loop = [].concat(_toConsumableArray$2(nodeStack.slice(nodeStack.indexOf(node))), [node]).map(function (d) { + return idAccessor(d.data); + }); + if (!foundLoops.some(function (foundLoop) { + return foundLoop.length === loop.length && foundLoop.every(function (id, idx) { + return id === loop[idx]; + }); + })) { + foundLoops.push(loop); + onLoopError(loop); + } + return 1; // continue + } + if (currentDepth > node.depth) { + // Don't unnecessarily revisit chunks of the graph + node.depth = currentDepth; + traverse(node.out, [].concat(_toConsumableArray$2(nodeStack), [node]), currentDepth + (node.skip ? 0 : 1)); + } + }; + for (var i = 0, l = nodes.length; i < l; i++) { + if (_loop()) continue; + } + } + } + + // + + var DAG_LEVEL_NODE_RATIO = 2; + + // whenever styling props are changed that require a canvas redraw + var notifyRedraw = function notifyRedraw(_, state) { + return state.onNeedsRedraw && state.onNeedsRedraw(); + }; + var updDataPhotons = function updDataPhotons(_, state) { + if (!state.isShadow) { + // Add photon particles + var linkParticlesAccessor = index$2(state.linkDirectionalParticles); + state.graphData.links.forEach(function (link) { + var numPhotons = Math.round(Math.abs(linkParticlesAccessor(link))); + if (numPhotons) { + link.__photons = _toConsumableArray$2(Array(numPhotons)).map(function () { + return {}; + }); + } else { + delete link.__photons; + } + }); + } + }; + var CanvasForceGraph = index$3({ + props: { + graphData: { + "default": { + nodes: [], + links: [] + }, + onChange: function onChange(_, state) { + state.engineRunning = false; // Pause simulation + updDataPhotons(_, state); + } + }, + dagMode: { + onChange: function onChange(dagMode, state) { + // td, bu, lr, rl, radialin, radialout + !dagMode && (state.graphData.nodes || []).forEach(function (n) { + return n.fx = n.fy = undefined; + }); // unfix nodes when disabling dag mode + } + }, + + dagLevelDistance: {}, + dagNodeFilter: { + "default": function _default(node) { + return true; + } + }, + onDagError: { + triggerUpdate: false + }, + nodeRelSize: { + "default": 4, + triggerUpdate: false, + onChange: notifyRedraw + }, + // area per val unit + nodeId: { + "default": 'id' + }, + nodeVal: { + "default": 'val', + triggerUpdate: false, + onChange: notifyRedraw + }, + nodeColor: { + "default": 'color', + triggerUpdate: false, + onChange: notifyRedraw + }, + nodeAutoColorBy: {}, + nodeCanvasObject: { + triggerUpdate: false, + onChange: notifyRedraw + }, + nodeCanvasObjectMode: { + "default": function _default() { + return 'replace'; + }, + triggerUpdate: false, + onChange: notifyRedraw + }, + nodeVisibility: { + "default": true, + triggerUpdate: false, + onChange: notifyRedraw + }, + linkSource: { + "default": 'source' + }, + linkTarget: { + "default": 'target' + }, + linkVisibility: { + "default": true, + triggerUpdate: false, + onChange: notifyRedraw + }, + linkColor: { + "default": 'color', + triggerUpdate: false, + onChange: notifyRedraw + }, + linkAutoColorBy: {}, + linkLineDash: { + triggerUpdate: false, + onChange: notifyRedraw + }, + linkWidth: { + "default": 1, + triggerUpdate: false, + onChange: notifyRedraw + }, + linkCurvature: { + "default": 0, + triggerUpdate: false, + onChange: notifyRedraw + }, + linkCanvasObject: { + triggerUpdate: false, + onChange: notifyRedraw + }, + linkCanvasObjectMode: { + "default": function _default() { + return 'replace'; + }, + triggerUpdate: false, + onChange: notifyRedraw + }, + linkDirectionalArrowLength: { + "default": 0, + triggerUpdate: false, + onChange: notifyRedraw + }, + linkDirectionalArrowColor: { + triggerUpdate: false, + onChange: notifyRedraw + }, + linkDirectionalArrowRelPos: { + "default": 0.5, + triggerUpdate: false, + onChange: notifyRedraw + }, + // value between 0<>1 indicating the relative pos along the (exposed) line + linkDirectionalParticles: { + "default": 0, + triggerUpdate: false, + onChange: updDataPhotons + }, + // animate photons travelling in the link direction + linkDirectionalParticleSpeed: { + "default": 0.01, + triggerUpdate: false + }, + // in link length ratio per frame + linkDirectionalParticleWidth: { + "default": 4, + triggerUpdate: false + }, + linkDirectionalParticleColor: { + triggerUpdate: false + }, + globalScale: { + "default": 1, + triggerUpdate: false + }, + d3AlphaMin: { + "default": 0, + triggerUpdate: false + }, + d3AlphaDecay: { + "default": 0.0228, + triggerUpdate: false, + onChange: function onChange(alphaDecay, state) { + state.forceLayout.alphaDecay(alphaDecay); + } + }, + d3AlphaTarget: { + "default": 0, + triggerUpdate: false, + onChange: function onChange(alphaTarget, state) { + state.forceLayout.alphaTarget(alphaTarget); + } + }, + d3VelocityDecay: { + "default": 0.4, + triggerUpdate: false, + onChange: function onChange(velocityDecay, state) { + state.forceLayout.velocityDecay(velocityDecay); + } + }, + warmupTicks: { + "default": 0, + triggerUpdate: false + }, + // how many times to tick the force engine at init before starting to render + cooldownTicks: { + "default": Infinity, + triggerUpdate: false + }, + cooldownTime: { + "default": 15000, + triggerUpdate: false + }, + // ms + onUpdate: { + "default": function _default() {}, + triggerUpdate: false + }, + onFinishUpdate: { + "default": function _default() {}, + triggerUpdate: false + }, + onEngineTick: { + "default": function _default() {}, + triggerUpdate: false + }, + onEngineStop: { + "default": function _default() {}, + triggerUpdate: false + }, + onNeedsRedraw: { + triggerUpdate: false + }, + isShadow: { + "default": false, + triggerUpdate: false + } + }, + methods: { + // Expose d3 forces for external manipulation + d3Force: function d3Force(state, forceName, forceFn) { + if (forceFn === undefined) { + return state.forceLayout.force(forceName); // Force getter + } + + state.forceLayout.force(forceName, forceFn); // Force setter + return this; + }, + d3ReheatSimulation: function d3ReheatSimulation(state) { + state.forceLayout.alpha(1); + this.resetCountdown(); + return this; + }, + // reset cooldown state + resetCountdown: function resetCountdown(state) { + state.cntTicks = 0; + state.startTickTime = new Date(); + state.engineRunning = true; + return this; + }, + isEngineRunning: function isEngineRunning(state) { + return !!state.engineRunning; + }, + tickFrame: function tickFrame(state) { + !state.isShadow && layoutTick(); + paintLinks(); + !state.isShadow && paintArrows(); + !state.isShadow && paintPhotons(); + paintNodes(); + return this; + + // + + function layoutTick() { + if (state.engineRunning) { + if (++state.cntTicks > state.cooldownTicks || new Date() - state.startTickTime > state.cooldownTime || state.d3AlphaMin > 0 && state.forceLayout.alpha() < state.d3AlphaMin) { + state.engineRunning = false; // Stop ticking graph + state.onEngineStop(); + } else { + state.forceLayout.tick(); // Tick it + state.onEngineTick(); + } + } + } + function paintNodes() { + var getVisibility = index$2(state.nodeVisibility); + var getVal = index$2(state.nodeVal); + var getColor = index$2(state.nodeColor); + var getNodeCanvasObjectMode = index$2(state.nodeCanvasObjectMode); + var ctx = state.ctx; + + // Draw wider nodes by 1px on shadow canvas for more precise hovering (due to boundary anti-aliasing) + var padAmount = state.isShadow / state.globalScale; + var visibleNodes = state.graphData.nodes.filter(getVisibility); + ctx.save(); + visibleNodes.forEach(function (node) { + var nodeCanvasObjectMode = getNodeCanvasObjectMode(node); + if (state.nodeCanvasObject && (nodeCanvasObjectMode === 'before' || nodeCanvasObjectMode === 'replace')) { + // Custom node before/replace paint + state.nodeCanvasObject(node, ctx, state.globalScale); + if (nodeCanvasObjectMode === 'replace') { + ctx.restore(); + return; + } + } + + // Draw wider nodes by 1px on shadow canvas for more precise hovering (due to boundary anti-aliasing) + var r = Math.sqrt(Math.max(0, getVal(node) || 1)) * state.nodeRelSize + padAmount; + ctx.beginPath(); + ctx.arc(node.x, node.y, r, 0, 2 * Math.PI, false); + ctx.fillStyle = getColor(node) || 'rgba(31, 120, 180, 0.92)'; + ctx.fill(); + if (state.nodeCanvasObject && nodeCanvasObjectMode === 'after') { + // Custom node after paint + state.nodeCanvasObject(node, state.ctx, state.globalScale); + } + }); + ctx.restore(); + } + function paintLinks() { + var getVisibility = index$2(state.linkVisibility); + var getColor = index$2(state.linkColor); + var getWidth = index$2(state.linkWidth); + var getLineDash = index$2(state.linkLineDash); + var getCurvature = index$2(state.linkCurvature); + var getLinkCanvasObjectMode = index$2(state.linkCanvasObjectMode); + var ctx = state.ctx; + + // Draw wider lines by 2px on shadow canvas for more precise hovering (due to boundary anti-aliasing) + var padAmount = state.isShadow * 2; + var visibleLinks = state.graphData.links.filter(getVisibility); + visibleLinks.forEach(calcLinkControlPoints); // calculate curvature control points for all visible links + + var beforeCustomLinks = [], + afterCustomLinks = [], + defaultPaintLinks = visibleLinks; + if (state.linkCanvasObject) { + var replaceCustomLinks = [], + otherCustomLinks = []; + visibleLinks.forEach(function (d) { + return ({ + before: beforeCustomLinks, + after: afterCustomLinks, + replace: replaceCustomLinks + }[getLinkCanvasObjectMode(d)] || otherCustomLinks).push(d); + }); + defaultPaintLinks = [].concat(_toConsumableArray$2(beforeCustomLinks), afterCustomLinks, otherCustomLinks); + beforeCustomLinks = beforeCustomLinks.concat(replaceCustomLinks); + } + + // Custom link before paints + ctx.save(); + beforeCustomLinks.forEach(function (link) { + return state.linkCanvasObject(link, ctx, state.globalScale); + }); + ctx.restore(); + + // Bundle strokes per unique color/width/dash for performance optimization + var linksPerColor = index(defaultPaintLinks, [getColor, getWidth, getLineDash]); + ctx.save(); + Object.entries(linksPerColor).forEach(function (_ref) { + var _ref2 = _slicedToArray$2(_ref, 2), + color = _ref2[0], + linksPerWidth = _ref2[1]; + var lineColor = !color || color === 'undefined' ? 'rgba(0,0,0,0.15)' : color; + Object.entries(linksPerWidth).forEach(function (_ref3) { + var _ref4 = _slicedToArray$2(_ref3, 2), + width = _ref4[0], + linesPerLineDash = _ref4[1]; + var lineWidth = (width || 1) / state.globalScale + padAmount; + Object.entries(linesPerLineDash).forEach(function (_ref5) { + var _ref6 = _slicedToArray$2(_ref5, 2); + _ref6[0]; + var links = _ref6[1]; + var lineDashSegments = getLineDash(links[0]); + ctx.beginPath(); + links.forEach(function (link) { + var start = link.source; + var end = link.target; + if (!start || !end || !start.hasOwnProperty('x') || !end.hasOwnProperty('x')) return; // skip invalid link + + ctx.moveTo(start.x, start.y); + var controlPoints = link.__controlPoints; + if (!controlPoints) { + // Straight line + ctx.lineTo(end.x, end.y); + } else { + // Use quadratic curves for regular lines and bezier for loops + ctx[controlPoints.length === 2 ? 'quadraticCurveTo' : 'bezierCurveTo'].apply(ctx, _toConsumableArray$2(controlPoints).concat([end.x, end.y])); + } + }); + ctx.strokeStyle = lineColor; + ctx.lineWidth = lineWidth; + ctx.setLineDash(lineDashSegments || []); + ctx.stroke(); + }); + }); + }); + ctx.restore(); + + // Custom link after paints + ctx.save(); + afterCustomLinks.forEach(function (link) { + return state.linkCanvasObject(link, ctx, state.globalScale); + }); + ctx.restore(); + + // + + function calcLinkControlPoints(link) { + var curvature = getCurvature(link); + if (!curvature) { + // straight line + link.__controlPoints = null; + return; + } + var start = link.source; + var end = link.target; + if (!start || !end || !start.hasOwnProperty('x') || !end.hasOwnProperty('x')) return; // skip invalid link + + var l = Math.sqrt(Math.pow(end.x - start.x, 2) + Math.pow(end.y - start.y, 2)); // line length + + if (l > 0) { + var a = Math.atan2(end.y - start.y, end.x - start.x); // line angle + var d = l * curvature; // control point distance + + var cp = { + // control point + x: (start.x + end.x) / 2 + d * Math.cos(a - Math.PI / 2), + y: (start.y + end.y) / 2 + d * Math.sin(a - Math.PI / 2) + }; + link.__controlPoints = [cp.x, cp.y]; + } else { + // Same point, draw a loop + var _d = curvature * 70; + link.__controlPoints = [end.x, end.y - _d, end.x + _d, end.y]; + } + } + } + function paintArrows() { + var ARROW_WH_RATIO = 1.6; + var ARROW_VLEN_RATIO = 0.2; + var getLength = index$2(state.linkDirectionalArrowLength); + var getRelPos = index$2(state.linkDirectionalArrowRelPos); + var getVisibility = index$2(state.linkVisibility); + var getColor = index$2(state.linkDirectionalArrowColor || state.linkColor); + var getNodeVal = index$2(state.nodeVal); + var ctx = state.ctx; + ctx.save(); + state.graphData.links.filter(getVisibility).forEach(function (link) { + var arrowLength = getLength(link); + if (!arrowLength || arrowLength < 0) return; + var start = link.source; + var end = link.target; + if (!start || !end || !start.hasOwnProperty('x') || !end.hasOwnProperty('x')) return; // skip invalid link + + var startR = Math.sqrt(Math.max(0, getNodeVal(start) || 1)) * state.nodeRelSize; + var endR = Math.sqrt(Math.max(0, getNodeVal(end) || 1)) * state.nodeRelSize; + var arrowRelPos = Math.min(1, Math.max(0, getRelPos(link))); + var arrowColor = getColor(link) || 'rgba(0,0,0,0.28)'; + var arrowHalfWidth = arrowLength / ARROW_WH_RATIO / 2; + + // Construct bezier for curved lines + var bzLine = link.__controlPoints && _construct(Bezier, [start.x, start.y].concat(_toConsumableArray$2(link.__controlPoints), [end.x, end.y])); + var getCoordsAlongLine = bzLine ? function (t) { + return bzLine.get(t); + } // get position along bezier line + : function (t) { + return { + // straight line: interpolate linearly + x: start.x + (end.x - start.x) * t || 0, + y: start.y + (end.y - start.y) * t || 0 + }; + }; + var lineLen = bzLine ? bzLine.length() : Math.sqrt(Math.pow(end.x - start.x, 2) + Math.pow(end.y - start.y, 2)); + var posAlongLine = startR + arrowLength + (lineLen - startR - endR - arrowLength) * arrowRelPos; + var arrowHead = getCoordsAlongLine(posAlongLine / lineLen); + var arrowTail = getCoordsAlongLine((posAlongLine - arrowLength) / lineLen); + var arrowTailVertex = getCoordsAlongLine((posAlongLine - arrowLength * (1 - ARROW_VLEN_RATIO)) / lineLen); + var arrowTailAngle = Math.atan2(arrowHead.y - arrowTail.y, arrowHead.x - arrowTail.x) - Math.PI / 2; + ctx.beginPath(); + ctx.moveTo(arrowHead.x, arrowHead.y); + ctx.lineTo(arrowTail.x + arrowHalfWidth * Math.cos(arrowTailAngle), arrowTail.y + arrowHalfWidth * Math.sin(arrowTailAngle)); + ctx.lineTo(arrowTailVertex.x, arrowTailVertex.y); + ctx.lineTo(arrowTail.x - arrowHalfWidth * Math.cos(arrowTailAngle), arrowTail.y - arrowHalfWidth * Math.sin(arrowTailAngle)); + ctx.fillStyle = arrowColor; + ctx.fill(); + }); + ctx.restore(); + } + function paintPhotons() { + var getNumPhotons = index$2(state.linkDirectionalParticles); + var getSpeed = index$2(state.linkDirectionalParticleSpeed); + var getDiameter = index$2(state.linkDirectionalParticleWidth); + var getVisibility = index$2(state.linkVisibility); + var getColor = index$2(state.linkDirectionalParticleColor || state.linkColor); + var ctx = state.ctx; + ctx.save(); + state.graphData.links.filter(getVisibility).forEach(function (link) { + var numCyclePhotons = getNumPhotons(link); + if (!link.hasOwnProperty('__photons') || !link.__photons.length) return; + var start = link.source; + var end = link.target; + if (!start || !end || !start.hasOwnProperty('x') || !end.hasOwnProperty('x')) return; // skip invalid link + + var particleSpeed = getSpeed(link); + var photons = link.__photons || []; + var photonR = Math.max(0, getDiameter(link) / 2) / Math.sqrt(state.globalScale); + var photonColor = getColor(link) || 'rgba(0,0,0,0.28)'; + ctx.fillStyle = photonColor; + + // Construct bezier for curved lines + var bzLine = link.__controlPoints ? _construct(Bezier, [start.x, start.y].concat(_toConsumableArray$2(link.__controlPoints), [end.x, end.y])) : null; + var cyclePhotonIdx = 0; + var needsCleanup = false; // whether some photons need to be removed from list + photons.forEach(function (photon) { + var singleHop = !!photon.__singleHop; + if (!photon.hasOwnProperty('__progressRatio')) { + photon.__progressRatio = singleHop ? 0 : cyclePhotonIdx / numCyclePhotons; + } + !singleHop && cyclePhotonIdx++; // increase regular photon index + + photon.__progressRatio += particleSpeed; + if (photon.__progressRatio >= 1) { + if (!singleHop) { + photon.__progressRatio = photon.__progressRatio % 1; + } else { + needsCleanup = true; + return; + } + } + var photonPosRatio = photon.__progressRatio; + var coords = bzLine ? bzLine.get(photonPosRatio) // get position along bezier line + : { + // straight line: interpolate linearly + x: start.x + (end.x - start.x) * photonPosRatio || 0, + y: start.y + (end.y - start.y) * photonPosRatio || 0 + }; + ctx.beginPath(); + ctx.arc(coords.x, coords.y, photonR, 0, 2 * Math.PI, false); + ctx.fill(); + }); + if (needsCleanup) { + // remove expired single hop photons + link.__photons = link.__photons.filter(function (photon) { + return !photon.__singleHop || photon.__progressRatio <= 1; + }); + } + }); + ctx.restore(); + } + }, + emitParticle: function emitParticle(state, link) { + if (link) { + !link.__photons && (link.__photons = []); + link.__photons.push({ + __singleHop: true + }); // add a single hop particle + } + + return this; + } + }, + stateInit: function stateInit() { + return { + forceLayout: d3ForceSimulation().force('link', d3ForceLink()).force('charge', d3ForceManyBody()).force('center', d3ForceCenter()).force('dagRadial', null).stop(), + engineRunning: false + }; + }, + init: function init(canvasCtx, state) { + // Main canvas object to manipulate + state.ctx = canvasCtx; + }, + update: function update(state) { + state.engineRunning = false; // Pause simulation + state.onUpdate(); + if (state.nodeAutoColorBy !== null) { + // Auto add color to uncolored nodes + autoColorObjects(state.graphData.nodes, index$2(state.nodeAutoColorBy), state.nodeColor); + } + if (state.linkAutoColorBy !== null) { + // Auto add color to uncolored links + autoColorObjects(state.graphData.links, index$2(state.linkAutoColorBy), state.linkColor); + } + + // parse links + state.graphData.links.forEach(function (link) { + link.source = link[state.linkSource]; + link.target = link[state.linkTarget]; + }); + + // Feed data to force-directed layout + state.forceLayout.stop().alpha(1) // re-heat the simulation + .nodes(state.graphData.nodes); + + // add links (if link force is still active) + var linkForce = state.forceLayout.force('link'); + if (linkForce) { + linkForce.id(function (d) { + return d[state.nodeId]; + }).links(state.graphData.links); + } + + // setup dag force constraints + var nodeDepths = state.dagMode && getDagDepths(state.graphData, function (node) { + return node[state.nodeId]; + }, { + nodeFilter: state.dagNodeFilter, + onLoopError: state.onDagError || undefined + }); + var maxDepth = Math.max.apply(Math, _toConsumableArray$2(Object.values(nodeDepths || []))); + var dagLevelDistance = state.dagLevelDistance || state.graphData.nodes.length / (maxDepth || 1) * DAG_LEVEL_NODE_RATIO * (['radialin', 'radialout'].indexOf(state.dagMode) !== -1 ? 0.7 : 1); + + // Fix nodes to x,y for dag mode + if (state.dagMode) { + var getFFn = function getFFn(fix, invert) { + return function (node) { + return !fix ? undefined : (nodeDepths[node[state.nodeId]] - maxDepth / 2) * dagLevelDistance * (invert ? -1 : 1); + }; + }; + var fxFn = getFFn(['lr', 'rl'].indexOf(state.dagMode) !== -1, state.dagMode === 'rl'); + var fyFn = getFFn(['td', 'bu'].indexOf(state.dagMode) !== -1, state.dagMode === 'bu'); + state.graphData.nodes.filter(state.dagNodeFilter).forEach(function (node) { + node.fx = fxFn(node); + node.fy = fyFn(node); + }); + } + + // Use radial force for radial dags + state.forceLayout.force('dagRadial', ['radialin', 'radialout'].indexOf(state.dagMode) !== -1 ? d3ForceRadial(function (node) { + var nodeDepth = nodeDepths[node[state.nodeId]] || -1; + return (state.dagMode === 'radialin' ? maxDepth - nodeDepth : nodeDepth) * dagLevelDistance; + }).strength(function (node) { + return state.dagNodeFilter(node) ? 1 : 0; + }) : null); + for (var i = 0; i < state.warmupTicks && !(state.d3AlphaMin > 0 && state.forceLayout.alpha() < state.d3AlphaMin); i++) { + state.forceLayout.tick(); + } // Initial ticks before starting to render + + this.resetCountdown(); + state.onFinishUpdate(); + } + }); + + function linkKapsule (kapsulePropNames, kapsuleType) { + var propNames = kapsulePropNames instanceof Array ? kapsulePropNames : [kapsulePropNames]; + var dummyK = new kapsuleType(); // To extract defaults + dummyK._destructor && dummyK._destructor(); + return { + linkProp: function linkProp(prop) { + // link property config + return { + "default": dummyK[prop](), + onChange: function onChange(v, state) { + propNames.forEach(function (propName) { + return state[propName][prop](v); + }); + }, + triggerUpdate: false + }; + }, + linkMethod: function linkMethod(method) { + // link method pass-through + return function (state) { + for (var _len = arguments.length, args = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) { + args[_key - 1] = arguments[_key]; + } + var returnVals = []; + propNames.forEach(function (propName) { + var kapsuleInstance = state[propName]; + var returnVal = kapsuleInstance[method].apply(kapsuleInstance, args); + if (returnVal !== kapsuleInstance) { + returnVals.push(returnVal); + } + }); + return returnVals.length ? returnVals[0] : this; // chain based on the parent object, not the inner kapsule + }; + } + }; + } + + var HOVER_CANVAS_THROTTLE_DELAY = 800; // ms to throttle shadow canvas updates for perf improvement + var ZOOM2NODES_FACTOR = 4; + + // Expose config from forceGraph + var bindFG = linkKapsule('forceGraph', CanvasForceGraph); + var bindBoth = linkKapsule(['forceGraph', 'shadowGraph'], CanvasForceGraph); + var linkedProps = Object.assign.apply(Object, _toConsumableArray$2(['nodeColor', 'nodeAutoColorBy', 'nodeCanvasObject', 'nodeCanvasObjectMode', 'linkColor', 'linkAutoColorBy', 'linkLineDash', 'linkWidth', 'linkCanvasObject', 'linkCanvasObjectMode', 'linkDirectionalArrowLength', 'linkDirectionalArrowColor', 'linkDirectionalArrowRelPos', 'linkDirectionalParticles', 'linkDirectionalParticleSpeed', 'linkDirectionalParticleWidth', 'linkDirectionalParticleColor', 'dagMode', 'dagLevelDistance', 'dagNodeFilter', 'onDagError', 'd3AlphaMin', 'd3AlphaDecay', 'd3VelocityDecay', 'warmupTicks', 'cooldownTicks', 'cooldownTime', 'onEngineTick', 'onEngineStop'].map(function (p) { + return _defineProperty({}, p, bindFG.linkProp(p)); + })).concat(_toConsumableArray$2(['nodeRelSize', 'nodeId', 'nodeVal', 'nodeVisibility', 'linkSource', 'linkTarget', 'linkVisibility', 'linkCurvature'].map(function (p) { + return _defineProperty({}, p, bindBoth.linkProp(p)); + })))); + var linkedMethods = Object.assign.apply(Object, _toConsumableArray$2(['d3Force', 'd3ReheatSimulation', 'emitParticle'].map(function (p) { + return _defineProperty({}, p, bindFG.linkMethod(p)); + }))); + function adjustCanvasSize(state) { + if (state.canvas) { + var curWidth = state.canvas.width; + var curHeight = state.canvas.height; + if (curWidth === 300 && curHeight === 150) { + // Default canvas dimensions + curWidth = curHeight = 0; + } + var pxScale = window.devicePixelRatio; // 2 on retina displays + curWidth /= pxScale; + curHeight /= pxScale; + + // Resize canvases + [state.canvas, state.shadowCanvas].forEach(function (canvas) { + // Element size + canvas.style.width = "".concat(state.width, "px"); + canvas.style.height = "".concat(state.height, "px"); + + // Memory size (scaled to avoid blurriness) + canvas.width = state.width * pxScale; + canvas.height = state.height * pxScale; + + // Normalize coordinate system to use css pixels (on init only) + if (!curWidth && !curHeight) { + canvas.getContext('2d').scale(pxScale, pxScale); + } + }); + + // Relative center panning based on 0,0 + var k = transform(state.canvas).k; + state.zoom.translateBy(state.zoom.__baseElem, (state.width - curWidth) / 2 / k, (state.height - curHeight) / 2 / k); + state.needsRedraw = true; + } + } + function resetTransform(ctx) { + var pxRatio = window.devicePixelRatio; + ctx.setTransform(pxRatio, 0, 0, pxRatio, 0, 0); + } + function clearCanvas(ctx, width, height) { + ctx.save(); + resetTransform(ctx); // reset transform + ctx.clearRect(0, 0, width, height); + ctx.restore(); //restore transforms + } + + // + + var forceGraph = index$3({ + props: _objectSpread2({ + width: { + "default": window.innerWidth, + onChange: function onChange(_, state) { + return adjustCanvasSize(state); + }, + triggerUpdate: false + }, + height: { + "default": window.innerHeight, + onChange: function onChange(_, state) { + return adjustCanvasSize(state); + }, + triggerUpdate: false + }, + graphData: { + "default": { + nodes: [], + links: [] + }, + onChange: function onChange(d, state) { + [{ + type: 'Node', + objs: d.nodes + }, { + type: 'Link', + objs: d.links + }].forEach(hexIndex); + state.forceGraph.graphData(d); + state.shadowGraph.graphData(d); + function hexIndex(_ref4) { + var type = _ref4.type, + objs = _ref4.objs; + objs.filter(function (d) { + if (!d.hasOwnProperty('__indexColor')) return true; + var cur = state.colorTracker.lookup(d.__indexColor); + return !cur || !cur.hasOwnProperty('d') || cur.d !== d; + }).forEach(function (d) { + // store object lookup color + d.__indexColor = state.colorTracker.register({ + type: type, + d: d + }); + }); + } + }, + triggerUpdate: false + }, + backgroundColor: { + onChange: function onChange(color, state) { + state.canvas && color && (state.canvas.style.background = color); + }, + triggerUpdate: false + }, + nodeLabel: { + "default": 'name', + triggerUpdate: false + }, + nodePointerAreaPaint: { + onChange: function onChange(paintFn, state) { + state.shadowGraph.nodeCanvasObject(!paintFn ? null : function (node, ctx, globalScale) { + return paintFn(node, node.__indexColor, ctx, globalScale); + }); + state.flushShadowCanvas && state.flushShadowCanvas(); + }, + triggerUpdate: false + }, + linkPointerAreaPaint: { + onChange: function onChange(paintFn, state) { + state.shadowGraph.linkCanvasObject(!paintFn ? null : function (link, ctx, globalScale) { + return paintFn(link, link.__indexColor, ctx, globalScale); + }); + state.flushShadowCanvas && state.flushShadowCanvas(); + }, + triggerUpdate: false + }, + linkLabel: { + "default": 'name', + triggerUpdate: false + }, + linkHoverPrecision: { + "default": 4, + triggerUpdate: false + }, + minZoom: { + "default": 0.01, + onChange: function onChange(minZoom, state) { + state.zoom.scaleExtent([minZoom, state.zoom.scaleExtent()[1]]); + }, + triggerUpdate: false + }, + maxZoom: { + "default": 1000, + onChange: function onChange(maxZoom, state) { + state.zoom.scaleExtent([state.zoom.scaleExtent()[0], maxZoom]); + }, + triggerUpdate: false + }, + enableNodeDrag: { + "default": true, + triggerUpdate: false + }, + enableZoomInteraction: { + "default": true, + triggerUpdate: false + }, + enablePanInteraction: { + "default": true, + triggerUpdate: false + }, + enableZoomPanInteraction: { + "default": true, + triggerUpdate: false + }, + // to be deprecated + enablePointerInteraction: { + "default": true, + onChange: function onChange(_, state) { + state.hoverObj = null; + }, + triggerUpdate: false + }, + autoPauseRedraw: { + "default": true, + triggerUpdate: false + }, + onNodeDrag: { + "default": function _default() {}, + triggerUpdate: false + }, + onNodeDragEnd: { + "default": function _default() {}, + triggerUpdate: false + }, + onNodeClick: { + triggerUpdate: false + }, + onNodeRightClick: { + triggerUpdate: false + }, + onNodeHover: { + triggerUpdate: false + }, + onLinkClick: { + triggerUpdate: false + }, + onLinkRightClick: { + triggerUpdate: false + }, + onLinkHover: { + triggerUpdate: false + }, + onBackgroundClick: { + triggerUpdate: false + }, + onBackgroundRightClick: { + triggerUpdate: false + }, + onZoom: { + triggerUpdate: false + }, + onZoomEnd: { + triggerUpdate: false + }, + onRenderFramePre: { + triggerUpdate: false + }, + onRenderFramePost: { + triggerUpdate: false + } + }, linkedProps), + aliases: { + // Prop names supported for backwards compatibility + stopAnimation: 'pauseAnimation' + }, + methods: _objectSpread2({ + graph2ScreenCoords: function graph2ScreenCoords(state, x, y) { + var t = transform(state.canvas); + return { + x: x * t.k + t.x, + y: y * t.k + t.y + }; + }, + screen2GraphCoords: function screen2GraphCoords(state, x, y) { + var t = transform(state.canvas); + return { + x: (x - t.x) / t.k, + y: (y - t.y) / t.k + }; + }, + centerAt: function centerAt(state, x, y, transitionDuration) { + if (!state.canvas) return null; // no canvas yet + + // setter + if (x !== undefined || y !== undefined) { + var finalPos = Object.assign({}, x !== undefined ? { + x: x + } : {}, y !== undefined ? { + y: y + } : {}); + if (!transitionDuration) { + // no animation + setCenter(finalPos); + } else { + new Tween(getCenter()).to(finalPos, transitionDuration).easing(Easing.Quadratic.Out).onUpdate(setCenter).start(); + } + return this; + } + + // getter + return getCenter(); + + // + + function getCenter() { + var t = transform(state.canvas); + return { + x: (state.width / 2 - t.x) / t.k, + y: (state.height / 2 - t.y) / t.k + }; + } + function setCenter(_ref5) { + var x = _ref5.x, + y = _ref5.y; + state.zoom.translateTo(state.zoom.__baseElem, x === undefined ? getCenter().x : x, y === undefined ? getCenter().y : y); + state.needsRedraw = true; + } + }, + zoom: function zoom(state, k, transitionDuration) { + if (!state.canvas) return null; // no canvas yet + + // setter + if (k !== undefined) { + if (!transitionDuration) { + // no animation + setZoom(k); + } else { + new Tween({ + k: getZoom() + }).to({ + k: k + }, transitionDuration).easing(Easing.Quadratic.Out).onUpdate(function (_ref6) { + var k = _ref6.k; + return setZoom(k); + }).start(); + } + return this; + } + + // getter + return getZoom(); + + // + + function getZoom() { + return transform(state.canvas).k; + } + function setZoom(k) { + state.zoom.scaleTo(state.zoom.__baseElem, k); + state.needsRedraw = true; + } + }, + zoomToFit: function zoomToFit(state) { + var transitionDuration = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0; + var padding = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 10; + for (var _len = arguments.length, bboxArgs = new Array(_len > 3 ? _len - 3 : 0), _key = 3; _key < _len; _key++) { + bboxArgs[_key - 3] = arguments[_key]; + } + var bbox = this.getGraphBbox.apply(this, bboxArgs); + if (bbox) { + var center = { + x: (bbox.x[0] + bbox.x[1]) / 2, + y: (bbox.y[0] + bbox.y[1]) / 2 + }; + var zoomK = Math.max(1e-12, Math.min(1e12, (state.width - padding * 2) / (bbox.x[1] - bbox.x[0]), (state.height - padding * 2) / (bbox.y[1] - bbox.y[0]))); + this.centerAt(center.x, center.y, transitionDuration); + this.zoom(zoomK, transitionDuration); + } + return this; + }, + getGraphBbox: function getGraphBbox(state) { + var nodeFilter = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : function () { + return true; + }; + var getVal = index$2(state.nodeVal); + var getR = function getR(node) { + return Math.sqrt(Math.max(0, getVal(node) || 1)) * state.nodeRelSize; + }; + var nodesPos = state.graphData.nodes.filter(nodeFilter).map(function (node) { + return { + x: node.x, + y: node.y, + r: getR(node) + }; + }); + return !nodesPos.length ? null : { + x: [min$1(nodesPos, function (node) { + return node.x - node.r; + }), max$1(nodesPos, function (node) { + return node.x + node.r; + })], + y: [min$1(nodesPos, function (node) { + return node.y - node.r; + }), max$1(nodesPos, function (node) { + return node.y + node.r; + })] + }; + }, + pauseAnimation: function pauseAnimation(state) { + if (state.animationFrameRequestId) { + cancelAnimationFrame(state.animationFrameRequestId); + state.animationFrameRequestId = null; + } + return this; + }, + resumeAnimation: function resumeAnimation(state) { + if (!state.animationFrameRequestId) { + this._animationCycle(); + } + return this; + }, + _destructor: function _destructor() { + this.pauseAnimation(); + this.graphData({ + nodes: [], + links: [] + }); + } + }, linkedMethods), + stateInit: function stateInit() { + return { + lastSetZoom: 1, + zoom: d3Zoom(), + forceGraph: new CanvasForceGraph(), + shadowGraph: new CanvasForceGraph().cooldownTicks(0).nodeColor('__indexColor').linkColor('__indexColor').isShadow(true), + colorTracker: new _default() // indexed objects for rgb lookup + }; + }, + + init: function init(domNode, state) { + var _this = this; + // Wipe DOM + domNode.innerHTML = ''; + + // Container anchor for canvas and tooltip + var container = document.createElement('div'); + container.classList.add('force-graph-container'); + container.style.position = 'relative'; + domNode.appendChild(container); + state.canvas = document.createElement('canvas'); + if (state.backgroundColor) state.canvas.style.background = state.backgroundColor; + container.appendChild(state.canvas); + state.shadowCanvas = document.createElement('canvas'); + + // Show shadow canvas + //state.shadowCanvas.style.position = 'absolute'; + //state.shadowCanvas.style.top = '0'; + //state.shadowCanvas.style.left = '0'; + //container.appendChild(state.shadowCanvas); + + var ctx = state.canvas.getContext('2d'); + var shadowCtx = state.shadowCanvas.getContext('2d', { + willReadFrequently: true + }); + var pointerPos = { + x: -1e12, + y: -1e12 + }; + var getObjUnderPointer = function getObjUnderPointer() { + var obj = null; + var pxScale = window.devicePixelRatio; + var px = pointerPos.x > 0 && pointerPos.y > 0 ? shadowCtx.getImageData(pointerPos.x * pxScale, pointerPos.y * pxScale, 1, 1) : null; + // Lookup object per pixel color + px && (obj = state.colorTracker.lookup(px.data)); + return obj; + }; + + // Setup node drag interaction + d3Select(state.canvas).call(d3Drag().subject(function () { + if (!state.enableNodeDrag) { + return null; + } + var obj = getObjUnderPointer(); + return obj && obj.type === 'Node' ? obj.d : null; // Only drag nodes + }).on('start', function (ev) { + var obj = ev.subject; + obj.__initialDragPos = { + x: obj.x, + y: obj.y, + fx: obj.fx, + fy: obj.fy + }; + + // keep engine running at low intensity throughout drag + if (!ev.active) { + obj.fx = obj.x; + obj.fy = obj.y; // Fix points + } + + // drag cursor + state.canvas.classList.add('grabbable'); + }).on('drag', function (ev) { + var obj = ev.subject; + var initPos = obj.__initialDragPos; + var dragPos = ev; + var k = transform(state.canvas).k; + var translate = { + x: initPos.x + (dragPos.x - initPos.x) / k - obj.x, + y: initPos.y + (dragPos.y - initPos.y) / k - obj.y + }; + + // Move fx/fy (and x/y) of nodes based on the scaled drag distance since the drag start + ['x', 'y'].forEach(function (c) { + return obj["f".concat(c)] = obj[c] = initPos[c] + (dragPos[c] - initPos[c]) / k; + }); + + // prevent freeze while dragging + state.forceGraph.d3AlphaTarget(0.3) // keep engine running at low intensity throughout drag + .resetCountdown(); // prevent freeze while dragging + + state.isPointerDragging = true; + obj.__dragged = true; + state.onNodeDrag(obj, translate); + }).on('end', function (ev) { + var obj = ev.subject; + var initPos = obj.__initialDragPos; + var translate = { + x: obj.x - initPos.x, + y: obj.y - initPos.y + }; + if (initPos.fx === undefined) { + obj.fx = undefined; + } + if (initPos.fy === undefined) { + obj.fy = undefined; + } + delete obj.__initialDragPos; + if (state.forceGraph.d3AlphaTarget()) { + state.forceGraph.d3AlphaTarget(0) // release engine low intensity + .resetCountdown(); // let the engine readjust after releasing fixed nodes + } + + // drag cursor + state.canvas.classList.remove('grabbable'); + state.isPointerDragging = false; + if (obj.__dragged) { + delete obj.__dragged; + state.onNodeDragEnd(obj, translate); + } + })); + + // Setup zoom / pan interaction + state.zoom(state.zoom.__baseElem = d3Select(state.canvas)); // Attach controlling elem for easy access + + state.zoom.__baseElem.on('dblclick.zoom', null); // Disable double-click to zoom + + state.zoom.filter(function (ev) { + return ( + // disable zoom interaction + !ev.button && state.enableZoomPanInteraction && (state.enableZoomInteraction || ev.type !== 'wheel') && (state.enablePanInteraction || ev.type === 'wheel') + ); + }).on('zoom', function (ev) { + var t = ev.transform; + [ctx, shadowCtx].forEach(function (c) { + resetTransform(c); + c.translate(t.x, t.y); + c.scale(t.k, t.k); + }); + state.onZoom && state.onZoom(_objectSpread2(_objectSpread2({}, t), _this.centerAt())); // report x,y coordinates relative to canvas center + state.needsRedraw = true; + }).on('end', function (ev) { + return state.onZoomEnd && state.onZoomEnd(_objectSpread2(_objectSpread2({}, ev.transform), _this.centerAt())); + }); + adjustCanvasSize(state); + state.forceGraph.onNeedsRedraw(function () { + return state.needsRedraw = true; + }).onFinishUpdate(function () { + // re-zoom, if still in default position (not user modified) + if (transform(state.canvas).k === state.lastSetZoom && state.graphData.nodes.length) { + state.zoom.scaleTo(state.zoom.__baseElem, state.lastSetZoom = ZOOM2NODES_FACTOR / Math.cbrt(state.graphData.nodes.length)); + state.needsRedraw = true; + } + }); + + // Setup tooltip + var toolTipElem = document.createElement('div'); + toolTipElem.classList.add('graph-tooltip'); + container.appendChild(toolTipElem); + + // Capture pointer coords on move or touchstart + ['pointermove', 'pointerdown'].forEach(function (evType) { + return container.addEventListener(evType, function (ev) { + if (evType === 'pointerdown') { + state.isPointerPressed = true; // track click state + state.pointerDownEvent = ev; + } + + // detect pointer drag on canvas pan + !state.isPointerDragging && ev.type === 'pointermove' && state.onBackgroundClick // only bother detecting drags this way if background clicks are enabled (so they don't trigger accidentally on canvas panning) + && (ev.pressure > 0 || state.isPointerPressed) // ev.pressure always 0 on Safari, so we use the isPointerPressed tracker + && (ev.pointerType !== 'touch' || ev.movementX === undefined || [ev.movementX, ev.movementY].some(function (m) { + return Math.abs(m) > 1; + })) // relax drag trigger sensitivity on touch events + && (state.isPointerDragging = true); + + // update the pointer pos + var offset = getOffset(container); + pointerPos.x = ev.pageX - offset.left; + pointerPos.y = ev.pageY - offset.top; + + // Move tooltip + toolTipElem.style.top = "".concat(pointerPos.y, "px"); + toolTipElem.style.left = "".concat(pointerPos.x, "px"); + + // adjust horizontal position to not exceed canvas boundaries + toolTipElem.style.transform = "translate(-".concat(pointerPos.x / state.width * 100, "%, ").concat( + // flip to above if near bottom + state.height - pointerPos.y < 100 ? 'calc(-100% - 8px)' : '21px', ")"); + + // + + function getOffset(el) { + var rect = el.getBoundingClientRect(), + scrollLeft = window.pageXOffset || document.documentElement.scrollLeft, + scrollTop = window.pageYOffset || document.documentElement.scrollTop; + return { + top: rect.top + scrollTop, + left: rect.left + scrollLeft + }; + } + }, { + passive: true + }); + }); + + // Handle click/touch events on nodes/links + container.addEventListener('pointerup', function (ev) { + state.isPointerPressed = false; + if (state.isPointerDragging) { + state.isPointerDragging = false; + return; // don't trigger click events after pointer drag (pan / node drag functionality) + } + + var cbEvents = [ev, state.pointerDownEvent]; + requestAnimationFrame(function () { + // trigger click events asynchronously, to allow hoverObj to be set (on frame) + if (ev.button === 0) { + // mouse left-click or touch + if (state.hoverObj) { + var fn = state["on".concat(state.hoverObj.type, "Click")]; + fn && fn.apply(void 0, [state.hoverObj.d].concat(cbEvents)); + } else { + state.onBackgroundClick && state.onBackgroundClick.apply(state, cbEvents); + } + } + if (ev.button === 2) { + // mouse right-click + if (state.hoverObj) { + var _fn = state["on".concat(state.hoverObj.type, "RightClick")]; + _fn && _fn.apply(void 0, [state.hoverObj.d].concat(cbEvents)); + } else { + state.onBackgroundRightClick && state.onBackgroundRightClick.apply(state, cbEvents); + } + } + }); + }, { + passive: true + }); + container.addEventListener('contextmenu', function (ev) { + if (!state.onBackgroundRightClick && !state.onNodeRightClick && !state.onLinkRightClick) return true; // default contextmenu behavior + ev.preventDefault(); + return false; + }); + state.forceGraph(ctx); + state.shadowGraph(shadowCtx); + + // + + var refreshShadowCanvas = throttle(function () { + // wipe canvas + clearCanvas(shadowCtx, state.width, state.height); + + // Adjust link hover area + state.shadowGraph.linkWidth(function (l) { + return index$2(state.linkWidth)(l) + state.linkHoverPrecision; + }); + + // redraw + var t = transform(state.canvas); + state.shadowGraph.globalScale(t.k).tickFrame(); + }, HOVER_CANVAS_THROTTLE_DELAY); + state.flushShadowCanvas = refreshShadowCanvas.flush; // hook to immediately invoke shadow canvas paint + + // Kick-off renderer + (this._animationCycle = function animate() { + // IIFE + var doRedraw = !state.autoPauseRedraw || !!state.needsRedraw || state.forceGraph.isEngineRunning() || state.graphData.links.some(function (d) { + return d.__photons && d.__photons.length; + }); + state.needsRedraw = false; + if (state.enablePointerInteraction) { + // Update tooltip and trigger onHover events + var obj = !state.isPointerDragging ? getObjUnderPointer() : null; // don't hover during drag + if (obj !== state.hoverObj) { + var prevObj = state.hoverObj; + var prevObjType = prevObj ? prevObj.type : null; + var objType = obj ? obj.type : null; + if (prevObjType && prevObjType !== objType) { + // Hover out + var fn = state["on".concat(prevObjType, "Hover")]; + fn && fn(null, prevObj.d); + } + if (objType) { + // Hover in + var _fn2 = state["on".concat(objType, "Hover")]; + _fn2 && _fn2(obj.d, prevObjType === objType ? prevObj.d : null); + } + var tooltipContent = obj ? index$2(state["".concat(obj.type.toLowerCase(), "Label")])(obj.d) || '' : ''; + toolTipElem.style.visibility = tooltipContent ? 'visible' : 'hidden'; + toolTipElem.innerHTML = tooltipContent; + + // set pointer if hovered object is clickable + state.canvas.classList[obj && state["on".concat(objType, "Click")] || !obj && state.onBackgroundClick ? 'add' : 'remove']('clickable'); + state.hoverObj = obj; + } + doRedraw && refreshShadowCanvas(); + } + if (doRedraw) { + // Wipe canvas + clearCanvas(ctx, state.width, state.height); + + // Frame cycle + var globalScale = transform(state.canvas).k; + state.onRenderFramePre && state.onRenderFramePre(ctx, globalScale); + state.forceGraph.globalScale(globalScale).tickFrame(); + state.onRenderFramePost && state.onRenderFramePost(ctx, globalScale); + } + update(); // update canvas animation tweens + + state.animationFrameRequestId = requestAnimationFrame(animate); + })(); + }, + update: function updateFn(state) {} + }); + + return forceGraph; + +})); +//# sourceMappingURL=force-graph.js.map diff --git a/hal-core/resources/web/js/lib/force-graph.min.js b/hal-core/resources/web/js/lib/force-graph.min.js new file mode 100644 index 00000000..42b88f34 --- /dev/null +++ b/hal-core/resources/web/js/lib/force-graph.min.js @@ -0,0 +1,5 @@ +// Version 1.43.4 force-graph - https://github.com/vasturiano/force-graph +!function(t,n){"object"==typeof exports&&"undefined"!=typeof module?module.exports=n():"function"==typeof define&&define.amd?define(n):(t="undefined"!=typeof globalThis?globalThis:t||self).ForceGraph=n()}(this,(function(){"use strict";function n(t,n){var e=Object.keys(t);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(t);n&&(r=r.filter((function(n){return Object.getOwnPropertyDescriptor(t,n).enumerable}))),e.push.apply(e,r)}return e}function e(t){for(var e=1;et.length)&&(n=t.length);for(var e=0,r=new Array(n);e=0&&"xmlns"!==(n=t.slice(0,e))&&(t=t.slice(e+1)),f.hasOwnProperty(n)?{space:f[n],local:t}:t}function p(t){return function(){var n=this.ownerDocument,e=this.namespaceURI;return e===h&&n.documentElement.namespaceURI===h?n.createElement(t):n.createElementNS(e,t)}}function g(t){return function(){return this.ownerDocument.createElementNS(t.space,t.local)}}function y(t){var n=d(t);return(n.local?g:p)(n)}function v(){}function _(t){return null==t?v:function(){return this.querySelector(t)}}function m(){return[]}function x(t){return null==t?m:function(){return this.querySelectorAll(t)}}function b(t){return function(){return function(t){return null==t?[]:Array.isArray(t)?t:Array.from(t)}(t.apply(this,arguments))}}function w(t){return function(){return this.matches(t)}}function k(t){return function(n){return n.matches(t)}}var M=Array.prototype.find;function z(){return this.firstElementChild}var A=Array.prototype.filter;function S(){return Array.from(this.children)}function C(t){return new Array(t.length)}function E(t,n){this.ownerDocument=t.ownerDocument,this.namespaceURI=t.namespaceURI,this._next=null,this._parent=t,this.__data__=n}function O(t,n,e,r,i,o){for(var a,u=0,s=n.length,l=o.length;un?1:t>=n?0:NaN}function R(t){return function(){this.removeAttribute(t)}}function D(t){return function(){this.removeAttributeNS(t.space,t.local)}}function I(t,n){return function(){this.setAttribute(t,n)}}function U(t,n){return function(){this.setAttributeNS(t.space,t.local,n)}}function F(t,n){return function(){var e=n.apply(this,arguments);null==e?this.removeAttribute(t):this.setAttribute(t,e)}}function L(t,n){return function(){var e=n.apply(this,arguments);null==e?this.removeAttributeNS(t.space,t.local):this.setAttributeNS(t.space,t.local,e)}}function q(t){return t.ownerDocument&&t.ownerDocument.defaultView||t.document&&t||t.defaultView}function B(t){return function(){this.style.removeProperty(t)}}function $(t,n,e){return function(){this.style.setProperty(t,n,e)}}function H(t,n,e){return function(){var r=n.apply(this,arguments);null==r?this.style.removeProperty(t):this.style.setProperty(t,r,e)}}function V(t,n){return t.style.getPropertyValue(n)||q(t).getComputedStyle(t,null).getPropertyValue(n)}function X(t){return function(){delete this[t]}}function G(t,n){return function(){this[t]=n}}function Y(t,n){return function(){var e=n.apply(this,arguments);null==e?delete this[t]:this[t]=e}}function W(t){return t.trim().split(/^|\s+/)}function Z(t){return t.classList||new Q(t)}function Q(t){this._node=t,this._names=W(t.getAttribute("class")||"")}function K(t,n){for(var e=Z(t),r=-1,i=n.length;++r=0&&(this._names.splice(n,1),this._node.setAttribute("class",this._names.join(" ")))},contains:function(t){return this._names.indexOf(t)>=0}};var xt=[null];function bt(t,n){this._groups=t,this._parents=n}function wt(){return new bt([[document.documentElement]],xt)}function kt(t){return"string"==typeof t?new bt([[document.querySelector(t)]],[document.documentElement]):new bt([[t]],xt)}function Mt(t,n){if(t=function(t){let n;for(;n=t.sourceEvent;)t=n;return t}(t),void 0===n&&(n=t.currentTarget),n){var e=n.ownerSVGElement||n;if(e.createSVGPoint){var r=e.createSVGPoint();return r.x=t.clientX,r.y=t.clientY,[(r=r.matrixTransform(n.getScreenCTM().inverse())).x,r.y]}if(n.getBoundingClientRect){var i=n.getBoundingClientRect();return[t.clientX-i.left-n.clientLeft,t.clientY-i.top-n.clientTop]}}return[t.pageX,t.pageY]}bt.prototype=wt.prototype={constructor:bt,select:function(t){"function"!=typeof t&&(t=_(t));for(var n=this._groups,e=n.length,r=new Array(e),i=0;i=x&&(x=m+1);!(_=y[x])&&++x=0;)(r=i[o])&&(a&&4^r.compareDocumentPosition(a)&&a.parentNode.insertBefore(r,a),a=r);return this},sort:function(t){function n(n,e){return n&&e?t(n.__data__,e.__data__):!n-!e}t||(t=T);for(var e=this._groups,r=e.length,i=new Array(r),o=0;o1?this.each((null==n?B:"function"==typeof n?H:$)(t,n,null==e?"":e)):V(this.node(),t)},property:function(t,n){return arguments.length>1?this.each((null==n?X:"function"==typeof n?Y:G)(t,n)):this.node()[t]},classed:function(t,n){var e=W(t+"");if(arguments.length<2){for(var r=Z(this.node()),i=-1,o=e.length;++i=0&&(n=t.slice(e+1),t=t.slice(0,e)),{type:t,name:n}}))}(t+""),a=o.length;if(!(arguments.length<2)){for(u=n?yt:gt,r=0;r{}};function At(){for(var t,n=0,e=arguments.length,r={};n=0&&(n=t.slice(e+1),t=t.slice(0,e)),t&&!r.hasOwnProperty(t))throw new Error("unknown type: "+t);return{type:t,name:n}}))),a=-1,u=o.length;if(!(arguments.length<2)){if(null!=n&&"function"!=typeof n)throw new Error("invalid callback: "+n);for(;++a0)for(var e,r,i=new Array(e),o=0;o()=>t;function It(t,{sourceEvent:n,subject:e,target:r,identifier:i,active:o,x:a,y:u,dx:s,dy:l,dispatch:c}){Object.defineProperties(this,{type:{value:t,enumerable:!0,configurable:!0},sourceEvent:{value:n,enumerable:!0,configurable:!0},subject:{value:e,enumerable:!0,configurable:!0},target:{value:r,enumerable:!0,configurable:!0},identifier:{value:i,enumerable:!0,configurable:!0},active:{value:o,enumerable:!0,configurable:!0},x:{value:a,enumerable:!0,configurable:!0},y:{value:u,enumerable:!0,configurable:!0},dx:{value:s,enumerable:!0,configurable:!0},dy:{value:l,enumerable:!0,configurable:!0},_:{value:c}})}function Ut(t){return!t.ctrlKey&&!t.button}function Ft(){return this.parentNode}function Lt(t,n){return null==n?{x:t.x,y:t.y}:n}function qt(){return navigator.maxTouchPoints||"ontouchstart"in this}function Bt(t,n,e){t.prototype=n.prototype=e,e.constructor=t}function $t(t,n){var e=Object.create(t.prototype);for(var r in n)e[r]=n[r];return e}function Ht(){}It.prototype.on=function(){var t=this._.on.apply(this._,arguments);return t===this._?this:t};var Vt=.7,Xt=1/Vt,Gt="\\s*([+-]?\\d+)\\s*",Yt="\\s*([+-]?(?:\\d*\\.)?\\d+(?:[eE][+-]?\\d+)?)\\s*",Wt="\\s*([+-]?(?:\\d*\\.)?\\d+(?:[eE][+-]?\\d+)?)%\\s*",Zt=/^#([0-9a-f]{3,8})$/,Qt=new RegExp(`^rgb\\(${Gt},${Gt},${Gt}\\)$`),Kt=new RegExp(`^rgb\\(${Wt},${Wt},${Wt}\\)$`),Jt=new RegExp(`^rgba\\(${Gt},${Gt},${Gt},${Yt}\\)$`),tn=new RegExp(`^rgba\\(${Wt},${Wt},${Wt},${Yt}\\)$`),nn=new RegExp(`^hsl\\(${Yt},${Wt},${Wt}\\)$`),en=new RegExp(`^hsla\\(${Yt},${Wt},${Wt},${Yt}\\)$`),rn={aliceblue:15792383,antiquewhite:16444375,aqua:65535,aquamarine:8388564,azure:15794175,beige:16119260,bisque:16770244,black:0,blanchedalmond:16772045,blue:255,blueviolet:9055202,brown:10824234,burlywood:14596231,cadetblue:6266528,chartreuse:8388352,chocolate:13789470,coral:16744272,cornflowerblue:6591981,cornsilk:16775388,crimson:14423100,cyan:65535,darkblue:139,darkcyan:35723,darkgoldenrod:12092939,darkgray:11119017,darkgreen:25600,darkgrey:11119017,darkkhaki:12433259,darkmagenta:9109643,darkolivegreen:5597999,darkorange:16747520,darkorchid:10040012,darkred:9109504,darksalmon:15308410,darkseagreen:9419919,darkslateblue:4734347,darkslategray:3100495,darkslategrey:3100495,darkturquoise:52945,darkviolet:9699539,deeppink:16716947,deepskyblue:49151,dimgray:6908265,dimgrey:6908265,dodgerblue:2003199,firebrick:11674146,floralwhite:16775920,forestgreen:2263842,fuchsia:16711935,gainsboro:14474460,ghostwhite:16316671,gold:16766720,goldenrod:14329120,gray:8421504,green:32768,greenyellow:11403055,grey:8421504,honeydew:15794160,hotpink:16738740,indianred:13458524,indigo:4915330,ivory:16777200,khaki:15787660,lavender:15132410,lavenderblush:16773365,lawngreen:8190976,lemonchiffon:16775885,lightblue:11393254,lightcoral:15761536,lightcyan:14745599,lightgoldenrodyellow:16448210,lightgray:13882323,lightgreen:9498256,lightgrey:13882323,lightpink:16758465,lightsalmon:16752762,lightseagreen:2142890,lightskyblue:8900346,lightslategray:7833753,lightslategrey:7833753,lightsteelblue:11584734,lightyellow:16777184,lime:65280,limegreen:3329330,linen:16445670,magenta:16711935,maroon:8388608,mediumaquamarine:6737322,mediumblue:205,mediumorchid:12211667,mediumpurple:9662683,mediumseagreen:3978097,mediumslateblue:8087790,mediumspringgreen:64154,mediumturquoise:4772300,mediumvioletred:13047173,midnightblue:1644912,mintcream:16121850,mistyrose:16770273,moccasin:16770229,navajowhite:16768685,navy:128,oldlace:16643558,olive:8421376,olivedrab:7048739,orange:16753920,orangered:16729344,orchid:14315734,palegoldenrod:15657130,palegreen:10025880,paleturquoise:11529966,palevioletred:14381203,papayawhip:16773077,peachpuff:16767673,peru:13468991,pink:16761035,plum:14524637,powderblue:11591910,purple:8388736,rebeccapurple:6697881,red:16711680,rosybrown:12357519,royalblue:4286945,saddlebrown:9127187,salmon:16416882,sandybrown:16032864,seagreen:3050327,seashell:16774638,sienna:10506797,silver:12632256,skyblue:8900331,slateblue:6970061,slategray:7372944,slategrey:7372944,snow:16775930,springgreen:65407,steelblue:4620980,tan:13808780,teal:32896,thistle:14204888,tomato:16737095,turquoise:4251856,violet:15631086,wheat:16113331,white:16777215,whitesmoke:16119285,yellow:16776960,yellowgreen:10145074};function on(){return this.rgb().formatHex()}function an(){return this.rgb().formatRgb()}function un(t){var n,e;return t=(t+"").trim().toLowerCase(),(n=Zt.exec(t))?(e=n[1].length,n=parseInt(n[1],16),6===e?sn(n):3===e?new hn(n>>8&15|n>>4&240,n>>4&15|240&n,(15&n)<<4|15&n,1):8===e?ln(n>>24&255,n>>16&255,n>>8&255,(255&n)/255):4===e?ln(n>>12&15|n>>8&240,n>>8&15|n>>4&240,n>>4&15|240&n,((15&n)<<4|15&n)/255):null):(n=Qt.exec(t))?new hn(n[1],n[2],n[3],1):(n=Kt.exec(t))?new hn(255*n[1]/100,255*n[2]/100,255*n[3]/100,1):(n=Jt.exec(t))?ln(n[1],n[2],n[3],n[4]):(n=tn.exec(t))?ln(255*n[1]/100,255*n[2]/100,255*n[3]/100,n[4]):(n=nn.exec(t))?vn(n[1],n[2]/100,n[3]/100,1):(n=en.exec(t))?vn(n[1],n[2]/100,n[3]/100,n[4]):rn.hasOwnProperty(t)?sn(rn[t]):"transparent"===t?new hn(NaN,NaN,NaN,0):null}function sn(t){return new hn(t>>16&255,t>>8&255,255&t,1)}function ln(t,n,e,r){return r<=0&&(t=n=e=NaN),new hn(t,n,e,r)}function cn(t,n,e,r){return 1===arguments.length?((i=t)instanceof Ht||(i=un(i)),i?new hn((i=i.rgb()).r,i.g,i.b,i.opacity):new hn):new hn(t,n,e,null==r?1:r);var i}function hn(t,n,e,r){this.r=+t,this.g=+n,this.b=+e,this.opacity=+r}function fn(){return`#${yn(this.r)}${yn(this.g)}${yn(this.b)}`}function dn(){const t=pn(this.opacity);return`${1===t?"rgb(":"rgba("}${gn(this.r)}, ${gn(this.g)}, ${gn(this.b)}${1===t?")":`, ${t})`}`}function pn(t){return isNaN(t)?1:Math.max(0,Math.min(1,t))}function gn(t){return Math.max(0,Math.min(255,Math.round(t)||0))}function yn(t){return((t=gn(t))<16?"0":"")+t.toString(16)}function vn(t,n,e,r){return r<=0?t=n=e=NaN:e<=0||e>=1?t=n=NaN:n<=0&&(t=NaN),new mn(t,n,e,r)}function _n(t){if(t instanceof mn)return new mn(t.h,t.s,t.l,t.opacity);if(t instanceof Ht||(t=un(t)),!t)return new mn;if(t instanceof mn)return t;var n=(t=t.rgb()).r/255,e=t.g/255,r=t.b/255,i=Math.min(n,e,r),o=Math.max(n,e,r),a=NaN,u=o-i,s=(o+i)/2;return u?(a=n===o?(e-r)/u+6*(e0&&s<1?0:a,new mn(a,u,s,t.opacity)}function mn(t,n,e,r){this.h=+t,this.s=+n,this.l=+e,this.opacity=+r}function xn(t){return(t=(t||0)%360)<0?t+360:t}function bn(t){return Math.max(0,Math.min(1,t||0))}function wn(t,n,e){return 255*(t<60?n+(e-n)*t/60:t<180?e:t<240?n+(e-n)*(240-t)/60:n)}Bt(Ht,un,{copy(t){return Object.assign(new this.constructor,this,t)},displayable(){return this.rgb().displayable()},hex:on,formatHex:on,formatHex8:function(){return this.rgb().formatHex8()},formatHsl:function(){return _n(this).formatHsl()},formatRgb:an,toString:an}),Bt(hn,cn,$t(Ht,{brighter(t){return t=null==t?Xt:Math.pow(Xt,t),new hn(this.r*t,this.g*t,this.b*t,this.opacity)},darker(t){return t=null==t?Vt:Math.pow(Vt,t),new hn(this.r*t,this.g*t,this.b*t,this.opacity)},rgb(){return this},clamp(){return new hn(gn(this.r),gn(this.g),gn(this.b),pn(this.opacity))},displayable(){return-.5<=this.r&&this.r<255.5&&-.5<=this.g&&this.g<255.5&&-.5<=this.b&&this.b<255.5&&0<=this.opacity&&this.opacity<=1},hex:fn,formatHex:fn,formatHex8:function(){return`#${yn(this.r)}${yn(this.g)}${yn(this.b)}${yn(255*(isNaN(this.opacity)?1:this.opacity))}`},formatRgb:dn,toString:dn})),Bt(mn,(function(t,n,e,r){return 1===arguments.length?_n(t):new mn(t,n,e,null==r?1:r)}),$t(Ht,{brighter(t){return t=null==t?Xt:Math.pow(Xt,t),new mn(this.h,this.s,this.l*t,this.opacity)},darker(t){return t=null==t?Vt:Math.pow(Vt,t),new mn(this.h,this.s,this.l*t,this.opacity)},rgb(){var t=this.h%360+360*(this.h<0),n=isNaN(t)||isNaN(this.s)?0:this.s,e=this.l,r=e+(e<.5?e:1-e)*n,i=2*e-r;return new hn(wn(t>=240?t-240:t+120,i,r),wn(t,i,r),wn(t<120?t+240:t-120,i,r),this.opacity)},clamp(){return new mn(xn(this.h),bn(this.s),bn(this.l),pn(this.opacity))},displayable(){return(0<=this.s&&this.s<=1||isNaN(this.s))&&0<=this.l&&this.l<=1&&0<=this.opacity&&this.opacity<=1},formatHsl(){const t=pn(this.opacity);return`${1===t?"hsl(":"hsla("}${xn(this.h)}, ${100*bn(this.s)}%, ${100*bn(this.l)}%${1===t?")":`, ${t})`}`}}));var kn=t=>()=>t;function Mn(t){return 1==(t=+t)?zn:function(n,e){return e-n?function(t,n,e){return t=Math.pow(t,e),n=Math.pow(n,e)-t,e=1/e,function(r){return Math.pow(t+r*n,e)}}(n,e,t):kn(isNaN(n)?e:n)}}function zn(t,n){var e=n-t;return e?function(t,n){return function(e){return t+e*n}}(t,e):kn(isNaN(t)?n:t)}var An=function t(n){var e=Mn(n);function r(t,n){var r=e((t=cn(t)).r,(n=cn(n)).r),i=e(t.g,n.g),o=e(t.b,n.b),a=zn(t.opacity,n.opacity);return function(n){return t.r=r(n),t.g=i(n),t.b=o(n),t.opacity=a(n),t+""}}return r.gamma=t,r}(1);function Sn(t,n){return t=+t,n=+n,function(e){return t*(1-e)+n*e}}var Cn=/[-+]?(?:\d+\.?\d*|\.?\d+)(?:[eE][-+]?\d+)?/g,En=new RegExp(Cn.source,"g");function On(t,n){var e,r,i,o=Cn.lastIndex=En.lastIndex=0,a=-1,u=[],s=[];for(t+="",n+="";(e=Cn.exec(t))&&(r=En.exec(n));)(i=r.index)>o&&(i=n.slice(o,i),u[a]?u[a]+=i:u[++a]=i),(e=e[0])===(r=r[0])?u[a]?u[a]+=r:u[++a]=r:(u[++a]=null,s.push({i:a,x:Sn(e,r)})),o=En.lastIndex;return o180?n+=360:n-t>180&&(t+=360),o.push({i:e.push(i(e)+"rotate(",null,r)-2,x:Sn(t,n)})):n&&e.push(i(e)+"rotate("+n+r)}(o.rotate,a.rotate,u,s),function(t,n,e,o){t!==n?o.push({i:e.push(i(e)+"skewX(",null,r)-2,x:Sn(t,n)}):n&&e.push(i(e)+"skewX("+n+r)}(o.skewX,a.skewX,u,s),function(t,n,e,r,o,a){if(t!==e||n!==r){var u=o.push(i(o)+"scale(",null,",",null,")");a.push({i:u-4,x:Sn(t,e)},{i:u-2,x:Sn(n,r)})}else 1===e&&1===r||o.push(i(o)+"scale("+e+","+r+")")}(o.scaleX,o.scaleY,a.scaleX,a.scaleY,u,s),o=a=null,function(t){for(var n,e=-1,r=s.length;++e=0&&n._call.call(void 0,t),n=n._next;--Bn}()}finally{Bn=0,function(){var t,n,e=Fn,r=1/0;for(;e;)e._call?(r>e._time&&(r=e._time),t=e,e=e._next):(n=e._next,e._next=null,e=t?t._next=n:Fn=n);Ln=t,re(r)}(),Gn=0}}function ee(){var t=Wn.now(),n=t-Xn;n>Vn&&(Yn-=n,Xn=t)}function re(t){Bn||($n&&($n=clearTimeout($n)),t-Gn>24?(t<1/0&&($n=setTimeout(ne,t-Wn.now()-Yn)),Hn&&(Hn=clearInterval(Hn))):(Hn||(Xn=Wn.now(),Hn=setInterval(ee,Vn)),Bn=1,Zn(ne)))}function ie(t,n,e){var r=new Jn;return n=null==n?0:+n,r.restart((e=>{r.stop(),t(e+n)}),n,e),r}Jn.prototype=te.prototype={constructor:Jn,restart:function(t,n,e){if("function"!=typeof t)throw new TypeError("callback is not a function");e=(null==e?Qn():+e)+(null==n?0:+n),this._next||Ln===this||(Ln?Ln._next=this:Fn=this,Ln=this),this._call=t,this._time=e,re()},stop:function(){this._call&&(this._call=null,this._time=1/0,re())}};var oe=At("start","end","cancel","interrupt"),ae=[],ue=0,se=1,le=2,ce=3,he=4,fe=5,de=6;function pe(t,n,e,r,i,o){var a=t.__transition;if(a){if(e in a)return}else t.__transition={};!function(t,n,e){var r,i=t.__transition;function o(t){e.state=se,e.timer.restart(a,e.delay,e.time),e.delay<=t&&a(t-e.delay)}function a(o){var l,c,h,f;if(e.state!==se)return s();for(l in i)if((f=i[l]).name===e.name){if(f.state===ce)return ie(a);f.state===he?(f.state=de,f.timer.stop(),f.on.call("interrupt",t,t.__data__,f.index,f.group),delete i[l]):+lue)throw new Error("too late; already scheduled");return e}function ye(t,n){var e=ve(t,n);if(e.state>ce)throw new Error("too late; already running");return e}function ve(t,n){var e=t.__transition;if(!e||!(e=e[n]))throw new Error("transition not found");return e}function _e(t,n){var e,r,i,o=t.__transition,a=!0;if(o){for(i in n=null==n?null:n+"",o)(e=o[i]).name===n?(r=e.state>le&&e.state=0&&(t=t.slice(0,n)),!t||"start"===t}))}(n)?ge:ye;return function(){var a=o(this,t),u=a.on;u!==r&&(i=(r=u).copy()).on(n,e),a.on=i}}(e,t,n))},attr:function(t,n){var e=d(t),r="transform"===e?In:we;return this.attrTween(t,"function"==typeof n?(e.local?Ce:Se)(e,r,be(this,"attr."+t,n)):null==n?(e.local?Me:ke)(e):(e.local?Ae:ze)(e,r,n))},attrTween:function(t,n){var e="attr."+t;if(arguments.length<2)return(e=this.tween(e))&&e._value;if(null==n)return this.tween(e,null);if("function"!=typeof n)throw new Error;var r=d(t);return this.tween(e,(r.local?Ee:Oe)(r,n))},style:function(t,n,e){var r="transform"==(t+="")?Dn:we;return null==n?this.styleTween(t,function(t,n){var e,r,i;return function(){var o=V(this,t),a=(this.style.removeProperty(t),V(this,t));return o===a?null:o===e&&a===r?i:i=n(e=o,r=a)}}(t,r)).on("end.style."+t,De(t)):"function"==typeof n?this.styleTween(t,function(t,n,e){var r,i,o;return function(){var a=V(this,t),u=e(this),s=u+"";return null==u&&(this.style.removeProperty(t),s=u=V(this,t)),a===s?null:a===r&&s===i?o:(i=s,o=n(r=a,u))}}(t,r,be(this,"style."+t,n))).each(function(t,n){var e,r,i,o,a="style."+n,u="end."+a;return function(){var s=ye(this,t),l=s.on,c=null==s.value[a]?o||(o=De(n)):void 0;l===e&&i===c||(r=(e=l).copy()).on(u,i=c),s.on=r}}(this._id,t)):this.styleTween(t,function(t,n,e){var r,i,o=e+"";return function(){var a=V(this,t);return a===o?null:a===r?i:i=n(r=a,e)}}(t,r,n),e).on("end.style."+t,null)},styleTween:function(t,n,e){var r="style."+(t+="");if(arguments.length<2)return(r=this.tween(r))&&r._value;if(null==n)return this.tween(r,null);if("function"!=typeof n)throw new Error;return this.tween(r,function(t,n,e){var r,i;function o(){var o=n.apply(this,arguments);return o!==i&&(r=(i=o)&&function(t,n,e){return function(r){this.style.setProperty(t,n.call(this,r),e)}}(t,o,e)),r}return o._value=n,o}(t,n,null==e?"":e))},text:function(t){return this.tween("text","function"==typeof t?function(t){return function(){var n=t(this);this.textContent=null==n?"":n}}(be(this,"text",t)):function(t){return function(){this.textContent=t}}(null==t?"":t+""))},textTween:function(t){var n="text";if(arguments.length<1)return(n=this.tween(n))&&n._value;if(null==t)return this.tween(n,null);if("function"!=typeof t)throw new Error;return this.tween(n,function(t){var n,e;function r(){var r=t.apply(this,arguments);return r!==e&&(n=(e=r)&&function(t){return function(n){this.textContent=t.call(this,n)}}(r)),n}return r._value=t,r}(t))},remove:function(){return this.on("end.remove",function(t){return function(){var n=this.parentNode;for(var e in this.__transition)if(+e!==t)return;n&&n.removeChild(this)}}(this._id))},tween:function(t,n){var e=this._id;if(t+="",arguments.length<2){for(var r,i=ve(this.node(),e).tween,o=0,a=i.length;o()=>t;function He(t,{sourceEvent:n,target:e,transform:r,dispatch:i}){Object.defineProperties(this,{type:{value:t,enumerable:!0,configurable:!0},sourceEvent:{value:n,enumerable:!0,configurable:!0},target:{value:e,enumerable:!0,configurable:!0},transform:{value:r,enumerable:!0,configurable:!0},_:{value:i}})}function Ve(t,n,e){this.k=t,this.x=n,this.y=e}Ve.prototype={constructor:Ve,scale:function(t){return 1===t?this:new Ve(this.k*t,this.x,this.y)},translate:function(t,n){return 0===t&0===n?this:new Ve(this.k,this.x+this.k*t,this.y+this.k*n)},apply:function(t){return[t[0]*this.k+this.x,t[1]*this.k+this.y]},applyX:function(t){return t*this.k+this.x},applyY:function(t){return t*this.k+this.y},invert:function(t){return[(t[0]-this.x)/this.k,(t[1]-this.y)/this.k]},invertX:function(t){return(t-this.x)/this.k},invertY:function(t){return(t-this.y)/this.k},rescaleX:function(t){return t.copy().domain(t.range().map(this.invertX,this).map(t.invert,t))},rescaleY:function(t){return t.copy().domain(t.range().map(this.invertY,this).map(t.invert,t))},toString:function(){return"translate("+this.x+","+this.y+") scale("+this.k+")"}};var Xe=new Ve(1,0,0);function Ge(t){for(;!t.__zoom;)if(!(t=t.parentNode))return Xe;return t.__zoom}function Ye(t){t.stopImmediatePropagation()}function We(t){t.preventDefault(),t.stopImmediatePropagation()}function Ze(t){return!(t.ctrlKey&&"wheel"!==t.type||t.button)}function Qe(){var t=this;return t instanceof SVGElement?(t=t.ownerSVGElement||t).hasAttribute("viewBox")?[[(t=t.viewBox.baseVal).x,t.y],[t.x+t.width,t.y+t.height]]:[[0,0],[t.width.baseVal.value,t.height.baseVal.value]]:[[0,0],[t.clientWidth,t.clientHeight]]}function Ke(){return this.__zoom||Xe}function Je(t){return-t.deltaY*(1===t.deltaMode?.05:t.deltaMode?1:.002)*(t.ctrlKey?10:1)}function tr(){return navigator.maxTouchPoints||"ontouchstart"in this}function nr(t,n,e){var r=t.invertX(n[0][0])-e[0][0],i=t.invertX(n[1][0])-e[1][0],o=t.invertY(n[0][1])-e[0][1],a=t.invertY(n[1][1])-e[1][1];return t.translate(i>r?(r+i)/2:Math.min(0,r)||Math.max(0,i),a>o?(o+a)/2:Math.min(0,o)||Math.max(0,a))}function er(){var t,n,e,r=Ze,i=Qe,o=nr,a=Je,u=tr,s=[0,1/0],l=[[-1/0,-1/0],[1/0,1/0]],c=250,h=qn,f=At("start","zoom","end"),d=500,p=150,g=0,y=10;function v(t){t.property("__zoom",Ke).on("wheel.zoom",M,{passive:!1}).on("mousedown.zoom",z).on("dblclick.zoom",A).filter(u).on("touchstart.zoom",S).on("touchmove.zoom",C).on("touchend.zoom touchcancel.zoom",E).style("-webkit-tap-highlight-color","rgba(0,0,0,0)")}function _(t,n){return(n=Math.max(s[0],Math.min(s[1],n)))===t.k?t:new Ve(n,t.x,t.y)}function m(t,n,e){var r=n[0]-e[0]*t.k,i=n[1]-e[1]*t.k;return r===t.x&&i===t.y?t:new Ve(t.k,r,i)}function x(t){return[(+t[0][0]+ +t[1][0])/2,(+t[0][1]+ +t[1][1])/2]}function b(t,n,e,r){t.on("start.zoom",(function(){w(this,arguments).event(r).start()})).on("interrupt.zoom end.zoom",(function(){w(this,arguments).event(r).end()})).tween("zoom",(function(){var t=this,o=arguments,a=w(t,o).event(r),u=i.apply(t,o),s=null==e?x(u):"function"==typeof e?e.apply(t,o):e,l=Math.max(u[1][0]-u[0][0],u[1][1]-u[0][1]),c=t.__zoom,f="function"==typeof n?n.apply(t,o):n,d=h(c.invert(s).concat(l/c.k),f.invert(s).concat(l/f.k));return function(t){if(1===t)t=f;else{var n=d(t),e=l/n[2];t=new Ve(e,s[0]-n[0]*e,s[1]-n[1]*e)}a.zoom(null,t)}}))}function w(t,n,e){return!e&&t.__zooming||new k(t,n)}function k(t,n){this.that=t,this.args=n,this.active=0,this.sourceEvent=null,this.extent=i.apply(t,n),this.taps=0}function M(t,...n){if(r.apply(this,arguments)){var e=w(this,n).event(t),i=this.__zoom,u=Math.max(s[0],Math.min(s[1],i.k*Math.pow(2,a.apply(this,arguments)))),c=Mt(t);if(e.wheel)e.mouse[0][0]===c[0]&&e.mouse[0][1]===c[1]||(e.mouse[1]=i.invert(e.mouse[0]=c)),clearTimeout(e.wheel);else{if(i.k===u)return;e.mouse=[c,i.invert(c)],_e(this),e.start()}We(t),e.wheel=setTimeout((function(){e.wheel=null,e.end()}),p),e.zoom("mouse",o(m(_(i,u),e.mouse[0],e.mouse[1]),e.extent,l))}}function z(t,...n){if(!e&&r.apply(this,arguments)){var i=t.currentTarget,a=w(this,n,!0).event(t),u=kt(t.view).on("mousemove.zoom",(function(t){if(We(t),!a.moved){var n=t.clientX-c,e=t.clientY-h;a.moved=n*n+e*e>g}a.event(t).zoom("mouse",o(m(a.that.__zoom,a.mouse[0]=Mt(t,i),a.mouse[1]),a.extent,l))}),!0).on("mouseup.zoom",(function(t){u.on("mousemove.zoom mouseup.zoom",null),Rt(t.view,a.moved),We(t),a.event(t).end()}),!0),s=Mt(t,i),c=t.clientX,h=t.clientY;Tt(t.view),Ye(t),a.mouse=[s,this.__zoom.invert(s)],_e(this),a.start()}}function A(t,...n){if(r.apply(this,arguments)){var e=this.__zoom,a=Mt(t.changedTouches?t.changedTouches[0]:t,this),u=e.invert(a),s=e.k*(t.shiftKey?.5:2),h=o(m(_(e,s),a,u),i.apply(this,n),l);We(t),c>0?kt(this).transition().duration(c).call(b,h,a,t):kt(this).call(v.transform,h,a,t)}}function S(e,...i){if(r.apply(this,arguments)){var o,a,u,s,l=e.touches,c=l.length,h=w(this,i,e.changedTouches.length===c).event(e);for(Ye(e),a=0;a=n)&&(e=n);else{let r=-1;for(let i of t)null!=(i=n(i,++r,t))&&(e=i)&&(e=i)}return e}function ur(t,n){let e;if(void 0===n)for(const n of t)null!=n&&(e>n||void 0===e&&n>=n)&&(e=n);else{let r=-1;for(let i of t)null!=(i=n(i,++r,t))&&(e>i||void 0===e&&i>=i)&&(e=i)}return e}var sr="object"==typeof global&&global&&global.Object===Object&&global,lr="object"==typeof self&&self&&self.Object===Object&&self,cr=sr||lr||Function("return this")(),hr=cr.Symbol,fr=Object.prototype,dr=fr.hasOwnProperty,pr=fr.toString,gr=hr?hr.toStringTag:void 0;var yr=Object.prototype.toString;var vr="[object Null]",_r="[object Undefined]",mr=hr?hr.toStringTag:void 0;function xr(t){return null==t?void 0===t?_r:vr:mr&&mr in Object(t)?function(t){var n=dr.call(t,gr),e=t[gr];try{t[gr]=void 0;var r=!0}catch(t){}var i=pr.call(t);return r&&(n?t[gr]=e:delete t[gr]),i}(t):function(t){return yr.call(t)}(t)}var br="[object Symbol]";var wr=/\s/;var kr=/^\s+/;function Mr(t){return t?t.slice(0,function(t){for(var n=t.length;n--&&wr.test(t.charAt(n)););return n}(t)+1).replace(kr,""):t}function zr(t){var n=typeof t;return null!=t&&("object"==n||"function"==n)}var Ar=NaN,Sr=/^[-+]0x[0-9a-f]+$/i,Cr=/^0b[01]+$/i,Er=/^0o[0-7]+$/i,Or=parseInt;function Nr(t){if("number"==typeof t)return t;if(function(t){return"symbol"==typeof t||function(t){return null!=t&&"object"==typeof t}(t)&&xr(t)==br}(t))return Ar;if(zr(t)){var n="function"==typeof t.valueOf?t.valueOf():t;t=zr(n)?n+"":n}if("string"!=typeof t)return 0===t?t:+t;t=Mr(t);var e=Cr.test(t);return e||Er.test(t)?Or(t.slice(2),e?2:8):Sr.test(t)?Ar:+t}var Pr=function(){return cr.Date.now()},jr="Expected a function",Tr=Math.max,Rr=Math.min;function Dr(t,n,e){var r,i,o,a,u,s,l=0,c=!1,h=!1,f=!0;if("function"!=typeof t)throw new TypeError(jr);function d(n){var e=r,o=i;return r=i=void 0,l=n,a=t.apply(o,e)}function p(t){var e=t-s;return void 0===s||e>=n||e<0||h&&t-l>=o}function g(){var t=Pr();if(p(t))return y(t);u=setTimeout(g,function(t){var e=n-(t-s);return h?Rr(e,o-(t-l)):e}(t))}function y(t){return u=void 0,f&&r?d(t):(r=i=void 0,a)}function v(){var t=Pr(),e=p(t);if(r=arguments,i=this,s=t,e){if(void 0===u)return function(t){return l=t,u=setTimeout(g,n),c?d(t):a}(s);if(h)return clearTimeout(u),u=setTimeout(g,n),d(s)}return void 0===u&&(u=setTimeout(g,n)),a}return n=Nr(n)||0,zr(e)&&(c=!!e.leading,o=(h="maxWait"in e)?Tr(Nr(e.maxWait)||0,n):o,f="trailing"in e?!!e.trailing:f),v.cancel=function(){void 0!==u&&clearTimeout(u),l=0,r=s=i=u=void 0},v.flush=function(){return void 0===u?a:y(Pr())},v}var Ir=Object.freeze({Linear:Object.freeze({None:function(t){return t},In:function(t){return this.None(t)},Out:function(t){return this.None(t)},InOut:function(t){return this.None(t)}}),Quadratic:Object.freeze({In:function(t){return t*t},Out:function(t){return t*(2-t)},InOut:function(t){return(t*=2)<1?.5*t*t:-.5*(--t*(t-2)-1)}}),Cubic:Object.freeze({In:function(t){return t*t*t},Out:function(t){return--t*t*t+1},InOut:function(t){return(t*=2)<1?.5*t*t*t:.5*((t-=2)*t*t+2)}}),Quartic:Object.freeze({In:function(t){return t*t*t*t},Out:function(t){return 1- --t*t*t*t},InOut:function(t){return(t*=2)<1?.5*t*t*t*t:-.5*((t-=2)*t*t*t-2)}}),Quintic:Object.freeze({In:function(t){return t*t*t*t*t},Out:function(t){return--t*t*t*t*t+1},InOut:function(t){return(t*=2)<1?.5*t*t*t*t*t:.5*((t-=2)*t*t*t*t+2)}}),Sinusoidal:Object.freeze({In:function(t){return 1-Math.sin((1-t)*Math.PI/2)},Out:function(t){return Math.sin(t*Math.PI/2)},InOut:function(t){return.5*(1-Math.sin(Math.PI*(.5-t)))}}),Exponential:Object.freeze({In:function(t){return 0===t?0:Math.pow(1024,t-1)},Out:function(t){return 1===t?1:1-Math.pow(2,-10*t)},InOut:function(t){return 0===t?0:1===t?1:(t*=2)<1?.5*Math.pow(1024,t-1):.5*(2-Math.pow(2,-10*(t-1)))}}),Circular:Object.freeze({In:function(t){return 1-Math.sqrt(1-t*t)},Out:function(t){return Math.sqrt(1- --t*t)},InOut:function(t){return(t*=2)<1?-.5*(Math.sqrt(1-t*t)-1):.5*(Math.sqrt(1-(t-=2)*t)+1)}}),Elastic:Object.freeze({In:function(t){return 0===t?0:1===t?1:-Math.pow(2,10*(t-1))*Math.sin(5*(t-1.1)*Math.PI)},Out:function(t){return 0===t?0:1===t?1:Math.pow(2,-10*t)*Math.sin(5*(t-.1)*Math.PI)+1},InOut:function(t){return 0===t?0:1===t?1:(t*=2)<1?-.5*Math.pow(2,10*(t-1))*Math.sin(5*(t-1.1)*Math.PI):.5*Math.pow(2,-10*(t-1))*Math.sin(5*(t-1.1)*Math.PI)+1}}),Back:Object.freeze({In:function(t){var n=1.70158;return 1===t?1:t*t*((n+1)*t-n)},Out:function(t){var n=1.70158;return 0===t?0:--t*t*((n+1)*t+n)+1},InOut:function(t){var n=2.5949095;return(t*=2)<1?t*t*((n+1)*t-n)*.5:.5*((t-=2)*t*((n+1)*t+n)+2)}}),Bounce:Object.freeze({In:function(t){return 1-Ir.Bounce.Out(1-t)},Out:function(t){return t<1/2.75?7.5625*t*t:t<2/2.75?7.5625*(t-=1.5/2.75)*t+.75:t<2.5/2.75?7.5625*(t-=2.25/2.75)*t+.9375:7.5625*(t-=2.625/2.75)*t+.984375},InOut:function(t){return t<.5?.5*Ir.Bounce.In(2*t):.5*Ir.Bounce.Out(2*t-1)+.5}}),generatePow:function(t){return void 0===t&&(t=4),t=(t=t1e4?1e4:t,{In:function(n){return Math.pow(n,t)},Out:function(n){return 1-Math.pow(1-n,t)},InOut:function(n){return n<.5?Math.pow(2*n,t)/2:(1-Math.pow(2-2*n,t))/2+.5}}}}),Ur=function(){return performance.now()},Fr=function(){function t(){this._tweens={},this._tweensAddedDuringUpdate={}}return t.prototype.getAll=function(){var t=this;return Object.keys(this._tweens).map((function(n){return t._tweens[n]}))},t.prototype.removeAll=function(){this._tweens={}},t.prototype.add=function(t){this._tweens[t.getId()]=t,this._tweensAddedDuringUpdate[t.getId()]=t},t.prototype.remove=function(t){delete this._tweens[t.getId()],delete this._tweensAddedDuringUpdate[t.getId()]},t.prototype.update=function(t,n){void 0===t&&(t=Ur()),void 0===n&&(n=!1);var e=Object.keys(this._tweens);if(0===e.length)return!1;for(;e.length>0;){this._tweensAddedDuringUpdate={};for(var r=0;r1?o(t[e],t[e-1],e-r):o(t[i],t[i+1>e?e:i+1],r-i)},Bezier:function(t,n){for(var e=0,r=t.length-1,i=Math.pow,o=Lr.Utils.Bernstein,a=0;a<=r;a++)e+=i(1-n,r-a)*i(n,a)*t[a]*o(r,a);return e},CatmullRom:function(t,n){var e=t.length-1,r=e*n,i=Math.floor(r),o=Lr.Utils.CatmullRom;return t[0]===t[e]?(n<0&&(i=Math.floor(r=e*(1+n))),o(t[(i-1+e)%e],t[i],t[(i+1)%e],t[(i+2)%e],r-i)):n<0?t[0]-(o(t[0],t[0],t[1],t[1],-r)-t[0]):n>1?t[e]-(o(t[e],t[e],t[e-1],t[e-1],r-e)-t[e]):o(t[i?i-1:0],t[i],t[e1;r--)e*=r;return t[n]=e,e}}(),CatmullRom:function(t,n,e,r,i){var o=.5*(e-t),a=.5*(r-n),u=i*i;return(2*n-2*e+o+a)*(i*u)+(-3*n+3*e-2*o-a)*u+o*i+n}}},qr=function(){function t(){}return t.nextId=function(){return t._nextId++},t._nextId=0,t}(),Br=new Fr,$r=function(){function t(t,n){void 0===n&&(n=Br),this._object=t,this._group=n,this._isPaused=!1,this._pauseStart=0,this._valuesStart={},this._valuesEnd={},this._valuesStartRepeat={},this._duration=1e3,this._isDynamic=!1,this._initialRepeat=0,this._repeat=0,this._yoyo=!1,this._isPlaying=!1,this._reversed=!1,this._delayTime=0,this._startTime=0,this._easingFunction=Ir.Linear.None,this._interpolationFunction=Lr.Linear,this._chainedTweens=[],this._onStartCallbackFired=!1,this._onEveryStartCallbackFired=!1,this._id=qr.nextId(),this._isChainStopped=!1,this._propertiesAreSetUp=!1,this._goToEnd=!1}return t.prototype.getId=function(){return this._id},t.prototype.isPlaying=function(){return this._isPlaying},t.prototype.isPaused=function(){return this._isPaused},t.prototype.to=function(t,n){if(void 0===n&&(n=1e3),this._isPlaying)throw new Error("Can not call Tween.to() while Tween is already started or paused. Stop the Tween first.");return this._valuesEnd=t,this._propertiesAreSetUp=!1,this._duration=n,this},t.prototype.duration=function(t){return void 0===t&&(t=1e3),this._duration=t,this},t.prototype.dynamic=function(t){return void 0===t&&(t=!1),this._isDynamic=t,this},t.prototype.start=function(t,n){if(void 0===t&&(t=Ur()),void 0===n&&(n=!1),this._isPlaying)return this;if(this._group&&this._group.add(this),this._repeat=this._initialRepeat,this._reversed)for(var e in this._reversed=!1,this._valuesStartRepeat)this._swapEndStartRepeatValues(e),this._valuesStart[e]=this._valuesStartRepeat[e];if(this._isPlaying=!0,this._isPaused=!1,this._onStartCallbackFired=!1,this._onEveryStartCallbackFired=!1,this._isChainStopped=!1,this._startTime=t,this._startTime+=this._delayTime,!this._propertiesAreSetUp||n){if(this._propertiesAreSetUp=!0,!this._isDynamic){var r={};for(var i in this._valuesEnd)r[i]=this._valuesEnd[i];this._valuesEnd=r}this._setupProperties(this._object,this._valuesStart,this._valuesEnd,this._valuesStartRepeat,n)}return this},t.prototype.startFromCurrentValues=function(t){return this.start(t,!0)},t.prototype._setupProperties=function(t,n,e,r,i){for(var o in e){var a=t[o],u=Array.isArray(a),s=u?"array":typeof a,l=!u&&Array.isArray(e[o]);if("undefined"!==s&&"function"!==s){if(l){if(0===(y=e[o]).length)continue;for(var c=[a],h=0,f=y.length;hi)return!1;n&&this.start(t,!0)}if(this._goToEnd=!1,t1?1:r;var o=this._easingFunction(r);if(this._updateProperties(this._object,this._valuesStart,this._valuesEnd,o),this._onUpdateCallback&&this._onUpdateCallback(this._object,r),1===r){if(this._repeat>0){for(e in isFinite(this._repeat)&&this._repeat--,this._valuesStartRepeat)this._yoyo||"string"!=typeof this._valuesEnd[e]||(this._valuesStartRepeat[e]=this._valuesStartRepeat[e]+parseFloat(this._valuesEnd[e])),this._yoyo&&this._swapEndStartRepeatValues(e),this._valuesStart[e]=this._valuesStartRepeat[e];return this._yoyo&&(this._reversed=!this._reversed),void 0!==this._repeatDelayTime?this._startTime=t+this._repeatDelayTime:this._startTime=t+this._delayTime,this._onRepeatCallback&&this._onRepeatCallback(this._object),this._onEveryStartCallbackFired=!1,!0}this._onCompleteCallback&&this._onCompleteCallback(this._object);for(var a=0,u=this._chainedTweens.length;at.length)&&(n=t.length);for(var e=0,r=new Array(n);e0&&void 0!==arguments[0]?arguments[0]:{},n=Object.assign({},e instanceof Function?e(t):e,{initialised:!1}),r={};function i(n){return o(n,t),u(),i}var o=function(t,e){c.call(i,t,n,e),n.initialised=!0},u=Dr((function(){n.initialised&&(f.call(i,n,r),r={})}),1);return d.forEach((function(t){i[t.name]=function(t){var e=t.name,o=t.triggerUpdate,a=void 0!==o&&o,s=t.onChange,l=void 0===s?function(t,n){}:s,c=t.defaultVal,h=void 0===c?null:c;return function(t){var o=n[e];if(!arguments.length)return o;var s=void 0===t?h:t;return n[e]=s,l.call(i,s,n,o),!r.hasOwnProperty(e)&&(r[e]=o),a&&u(),i}}(t)})),Object.keys(a).forEach((function(t){i[t]=function(){for(var e,r=arguments.length,o=new Array(r),u=0;u1&&(e-=1),e<1/6?t+6*(n-t)*e:e<.5?n:e<2/3?t+(n-t)*(2/3-e)*6:t}if(t=wi(t,360),n=wi(n,100),e=wi(e,100),0===n)r=i=o=e;else{var u=e<.5?e*(1+n):e+n-e*n,s=2*e-u;r=a(s,u,t+1/3),i=a(s,u,t),o=a(s,u,t-1/3)}return{r:255*r,g:255*i,b:255*o}}(t.h,r,o),a=!0,u="hsl"),t.hasOwnProperty("a")&&(e=t.a));var s,l,c;return e=bi(e),{ok:a,format:t.format||u,r:Math.min(255,Math.max(n.r,0)),g:Math.min(255,Math.max(n.g,0)),b:Math.min(255,Math.max(n.b,0)),a:e}}(t);this._originalInput=t,this._r=e.r,this._g=e.g,this._b=e.b,this._a=e.a,this._roundA=Math.round(100*this._a)/100,this._format=n.format||e.format,this._gradientType=n.gradientType,this._r<1&&(this._r=Math.round(this._r)),this._g<1&&(this._g=Math.round(this._g)),this._b<1&&(this._b=Math.round(this._b)),this._ok=e.ok}function ri(t,n,e){t=wi(t,255),n=wi(n,255),e=wi(e,255);var r,i,o=Math.max(t,n,e),a=Math.min(t,n,e),u=(o+a)/2;if(o==a)r=i=0;else{var s=o-a;switch(i=u>.5?s/(2-o-a):s/(o+a),o){case t:r=(n-e)/s+(n>1)+720)%360;--n;)r.h=(r.h+i)%360,o.push(ei(r));return o}function _i(t,n){n=n||6;for(var e=ei(t).toHsv(),r=e.h,i=e.s,o=e.v,a=[],u=1/n;n--;)a.push(ei({h:r,s:i,v:o})),o=(o+u)%1;return a}ei.prototype={isDark:function(){return this.getBrightness()<128},isLight:function(){return!this.isDark()},isValid:function(){return this._ok},getOriginalInput:function(){return this._originalInput},getFormat:function(){return this._format},getAlpha:function(){return this._a},getBrightness:function(){var t=this.toRgb();return(299*t.r+587*t.g+114*t.b)/1e3},getLuminance:function(){var t,n,e,r=this.toRgb();return t=r.r/255,n=r.g/255,e=r.b/255,.2126*(t<=.03928?t/12.92:Math.pow((t+.055)/1.055,2.4))+.7152*(n<=.03928?n/12.92:Math.pow((n+.055)/1.055,2.4))+.0722*(e<=.03928?e/12.92:Math.pow((e+.055)/1.055,2.4))},setAlpha:function(t){return this._a=bi(t),this._roundA=Math.round(100*this._a)/100,this},toHsv:function(){var t=ii(this._r,this._g,this._b);return{h:360*t.h,s:t.s,v:t.v,a:this._a}},toHsvString:function(){var t=ii(this._r,this._g,this._b),n=Math.round(360*t.h),e=Math.round(100*t.s),r=Math.round(100*t.v);return 1==this._a?"hsv("+n+", "+e+"%, "+r+"%)":"hsva("+n+", "+e+"%, "+r+"%, "+this._roundA+")"},toHsl:function(){var t=ri(this._r,this._g,this._b);return{h:360*t.h,s:t.s,l:t.l,a:this._a}},toHslString:function(){var t=ri(this._r,this._g,this._b),n=Math.round(360*t.h),e=Math.round(100*t.s),r=Math.round(100*t.l);return 1==this._a?"hsl("+n+", "+e+"%, "+r+"%)":"hsla("+n+", "+e+"%, "+r+"%, "+this._roundA+")"},toHex:function(t){return oi(this._r,this._g,this._b,t)},toHexString:function(t){return"#"+this.toHex(t)},toHex8:function(t){return function(t,n,e,r,i){var o=[zi(Math.round(t).toString(16)),zi(Math.round(n).toString(16)),zi(Math.round(e).toString(16)),zi(Si(r))];if(i&&o[0].charAt(0)==o[0].charAt(1)&&o[1].charAt(0)==o[1].charAt(1)&&o[2].charAt(0)==o[2].charAt(1)&&o[3].charAt(0)==o[3].charAt(1))return o[0].charAt(0)+o[1].charAt(0)+o[2].charAt(0)+o[3].charAt(0);return o.join("")}(this._r,this._g,this._b,this._a,t)},toHex8String:function(t){return"#"+this.toHex8(t)},toRgb:function(){return{r:Math.round(this._r),g:Math.round(this._g),b:Math.round(this._b),a:this._a}},toRgbString:function(){return 1==this._a?"rgb("+Math.round(this._r)+", "+Math.round(this._g)+", "+Math.round(this._b)+")":"rgba("+Math.round(this._r)+", "+Math.round(this._g)+", "+Math.round(this._b)+", "+this._roundA+")"},toPercentageRgb:function(){return{r:Math.round(100*wi(this._r,255))+"%",g:Math.round(100*wi(this._g,255))+"%",b:Math.round(100*wi(this._b,255))+"%",a:this._a}},toPercentageRgbString:function(){return 1==this._a?"rgb("+Math.round(100*wi(this._r,255))+"%, "+Math.round(100*wi(this._g,255))+"%, "+Math.round(100*wi(this._b,255))+"%)":"rgba("+Math.round(100*wi(this._r,255))+"%, "+Math.round(100*wi(this._g,255))+"%, "+Math.round(100*wi(this._b,255))+"%, "+this._roundA+")"},toName:function(){return 0===this._a?"transparent":!(this._a<1)&&(xi[oi(this._r,this._g,this._b,!0)]||!1)},toFilter:function(t){var n="#"+ai(this._r,this._g,this._b,this._a),e=n,r=this._gradientType?"GradientType = 1, ":"";if(t){var i=ei(t);e="#"+ai(i._r,i._g,i._b,i._a)}return"progid:DXImageTransform.Microsoft.gradient("+r+"startColorstr="+n+",endColorstr="+e+")"},toString:function(t){var n=!!t;t=t||this._format;var e=!1,r=this._a<1&&this._a>=0;return n||!r||"hex"!==t&&"hex6"!==t&&"hex3"!==t&&"hex4"!==t&&"hex8"!==t&&"name"!==t?("rgb"===t&&(e=this.toRgbString()),"prgb"===t&&(e=this.toPercentageRgbString()),"hex"!==t&&"hex6"!==t||(e=this.toHexString()),"hex3"===t&&(e=this.toHexString(!0)),"hex4"===t&&(e=this.toHex8String(!0)),"hex8"===t&&(e=this.toHex8String()),"name"===t&&(e=this.toName()),"hsl"===t&&(e=this.toHslString()),"hsv"===t&&(e=this.toHsvString()),e||this.toHexString()):"name"===t&&0===this._a?this.toName():this.toRgbString()},clone:function(){return ei(this.toString())},_applyModification:function(t,n){var e=t.apply(null,[this].concat([].slice.call(n)));return this._r=e._r,this._g=e._g,this._b=e._b,this.setAlpha(e._a),this},lighten:function(){return this._applyModification(ci,arguments)},brighten:function(){return this._applyModification(hi,arguments)},darken:function(){return this._applyModification(fi,arguments)},desaturate:function(){return this._applyModification(ui,arguments)},saturate:function(){return this._applyModification(si,arguments)},greyscale:function(){return this._applyModification(li,arguments)},spin:function(){return this._applyModification(di,arguments)},_applyCombination:function(t,n){return t.apply(null,[this].concat([].slice.call(n)))},analogous:function(){return this._applyCombination(vi,arguments)},complement:function(){return this._applyCombination(pi,arguments)},monochromatic:function(){return this._applyCombination(_i,arguments)},splitcomplement:function(){return this._applyCombination(yi,arguments)},triad:function(){return this._applyCombination(gi,[3])},tetrad:function(){return this._applyCombination(gi,[4])}},ei.fromRatio=function(t,n){if("object"==Jr(t)){var e={};for(var r in t)t.hasOwnProperty(r)&&(e[r]="a"===r?t[r]:Ai(t[r]));t=e}return ei(t,n)},ei.equals=function(t,n){return!(!t||!n)&&ei(t).toRgbString()==ei(n).toRgbString()},ei.random=function(){return ei.fromRatio({r:Math.random(),g:Math.random(),b:Math.random()})},ei.mix=function(t,n,e){e=0===e?0:e||50;var r=ei(t).toRgb(),i=ei(n).toRgb(),o=e/100;return ei({r:(i.r-r.r)*o+r.r,g:(i.g-r.g)*o+r.g,b:(i.b-r.b)*o+r.b,a:(i.a-r.a)*o+r.a})}, +// =4.5;break;case"AAlarge":i=o>=3;break;case"AAAsmall":i=o>=7}return i},ei.mostReadable=function(t,n,e){var r,i,o,a,u=null,s=0;i=(e=e||{}).includeFallbackColors,o=e.level,a=e.size;for(var l=0;ls&&(s=r,u=ei(n[l]));return ei.isReadable(t,u,{level:o,size:a})||!i?u:(e.includeFallbackColors=!1,ei.mostReadable(t,["#fff","#000"],e))};var mi=ei.names={aliceblue:"f0f8ff",antiquewhite:"faebd7",aqua:"0ff",aquamarine:"7fffd4",azure:"f0ffff",beige:"f5f5dc",bisque:"ffe4c4",black:"000",blanchedalmond:"ffebcd",blue:"00f",blueviolet:"8a2be2",brown:"a52a2a",burlywood:"deb887",burntsienna:"ea7e5d",cadetblue:"5f9ea0",chartreuse:"7fff00",chocolate:"d2691e",coral:"ff7f50",cornflowerblue:"6495ed",cornsilk:"fff8dc",crimson:"dc143c",cyan:"0ff",darkblue:"00008b",darkcyan:"008b8b",darkgoldenrod:"b8860b",darkgray:"a9a9a9",darkgreen:"006400",darkgrey:"a9a9a9",darkkhaki:"bdb76b",darkmagenta:"8b008b",darkolivegreen:"556b2f",darkorange:"ff8c00",darkorchid:"9932cc",darkred:"8b0000",darksalmon:"e9967a",darkseagreen:"8fbc8f",darkslateblue:"483d8b",darkslategray:"2f4f4f",darkslategrey:"2f4f4f",darkturquoise:"00ced1",darkviolet:"9400d3",deeppink:"ff1493",deepskyblue:"00bfff",dimgray:"696969",dimgrey:"696969",dodgerblue:"1e90ff",firebrick:"b22222",floralwhite:"fffaf0",forestgreen:"228b22",fuchsia:"f0f",gainsboro:"dcdcdc",ghostwhite:"f8f8ff",gold:"ffd700",goldenrod:"daa520",gray:"808080",green:"008000",greenyellow:"adff2f",grey:"808080",honeydew:"f0fff0",hotpink:"ff69b4",indianred:"cd5c5c",indigo:"4b0082",ivory:"fffff0",khaki:"f0e68c",lavender:"e6e6fa",lavenderblush:"fff0f5",lawngreen:"7cfc00",lemonchiffon:"fffacd",lightblue:"add8e6",lightcoral:"f08080",lightcyan:"e0ffff",lightgoldenrodyellow:"fafad2",lightgray:"d3d3d3",lightgreen:"90ee90",lightgrey:"d3d3d3",lightpink:"ffb6c1",lightsalmon:"ffa07a",lightseagreen:"20b2aa",lightskyblue:"87cefa",lightslategray:"789",lightslategrey:"789",lightsteelblue:"b0c4de",lightyellow:"ffffe0",lime:"0f0",limegreen:"32cd32",linen:"faf0e6",magenta:"f0f",maroon:"800000",mediumaquamarine:"66cdaa",mediumblue:"0000cd",mediumorchid:"ba55d3",mediumpurple:"9370db",mediumseagreen:"3cb371",mediumslateblue:"7b68ee",mediumspringgreen:"00fa9a",mediumturquoise:"48d1cc",mediumvioletred:"c71585",midnightblue:"191970",mintcream:"f5fffa",mistyrose:"ffe4e1",moccasin:"ffe4b5",navajowhite:"ffdead",navy:"000080",oldlace:"fdf5e6",olive:"808000",olivedrab:"6b8e23",orange:"ffa500",orangered:"ff4500",orchid:"da70d6",palegoldenrod:"eee8aa",palegreen:"98fb98",paleturquoise:"afeeee",palevioletred:"db7093",papayawhip:"ffefd5",peachpuff:"ffdab9",peru:"cd853f",pink:"ffc0cb",plum:"dda0dd",powderblue:"b0e0e6",purple:"800080",rebeccapurple:"663399",red:"f00",rosybrown:"bc8f8f",royalblue:"4169e1",saddlebrown:"8b4513",salmon:"fa8072",sandybrown:"f4a460",seagreen:"2e8b57",seashell:"fff5ee",sienna:"a0522d",silver:"c0c0c0",skyblue:"87ceeb",slateblue:"6a5acd",slategray:"708090",slategrey:"708090",snow:"fffafa",springgreen:"00ff7f",steelblue:"4682b4",tan:"d2b48c",teal:"008080",thistle:"d8bfd8",tomato:"ff6347",turquoise:"40e0d0",violet:"ee82ee",wheat:"f5deb3",white:"fff",whitesmoke:"f5f5f5",yellow:"ff0",yellowgreen:"9acd32"},xi=ei.hexNames=function(t){var n={};for(var e in t)t.hasOwnProperty(e)&&(n[t[e]]=e);return n}(mi);function bi(t){return t=parseFloat(t),(isNaN(t)||t<0||t>1)&&(t=1),t}function wi(t,n){(function(t){return"string"==typeof t&&-1!=t.indexOf(".")&&1===parseFloat(t)})(t)&&(t="100%");var e=function(t){return"string"==typeof t&&-1!=t.indexOf("%")}(t);return t=Math.min(n,Math.max(0,parseFloat(t))),e&&(t=parseInt(t*n,10)/100),Math.abs(t-n)<1e-6?1:t%n/parseFloat(n)}function ki(t){return Math.min(1,Math.max(0,t))}function Mi(t){return parseInt(t,16)}function zi(t){return 1==t.length?"0"+t:""+t}function Ai(t){return t<=1&&(t=100*t+"%"),t}function Si(t){return Math.round(255*parseFloat(t)).toString(16)}function Ci(t){return Mi(t)/255}var Ei,Oi,Ni,Pi=(Oi="[\\s|\\(]+("+(Ei="(?:[-\\+]?\\d*\\.\\d+%?)|(?:[-\\+]?\\d+%?)")+")[,|\\s]+("+Ei+")[,|\\s]+("+Ei+")\\s*\\)?",Ni="[\\s|\\(]+("+Ei+")[,|\\s]+("+Ei+")[,|\\s]+("+Ei+")[,|\\s]+("+Ei+")\\s*\\)?",{CSS_UNIT:new RegExp(Ei),rgb:new RegExp("rgb"+Oi),rgba:new RegExp("rgba"+Ni),hsl:new RegExp("hsl"+Oi),hsla:new RegExp("hsla"+Ni),hsv:new RegExp("hsv"+Oi),hsva:new RegExp("hsva"+Ni),hex3:/^#?([0-9a-fA-F]{1})([0-9a-fA-F]{1})([0-9a-fA-F]{1})$/,hex6:/^#?([0-9a-fA-F]{2})([0-9a-fA-F]{2})([0-9a-fA-F]{2})$/,hex4:/^#?([0-9a-fA-F]{1})([0-9a-fA-F]{1})([0-9a-fA-F]{1})([0-9a-fA-F]{1})$/,hex8:/^#?([0-9a-fA-F]{2})([0-9a-fA-F]{2})([0-9a-fA-F]{2})([0-9a-fA-F]{2})$/});function ji(t){return!!Pi.CSS_UNIT.exec(t)}function Ti(t,n){for(var e=0;et.length)&&(n=t.length);for(var e=0,r=new Array(n);e0&&void 0!==arguments[0]?arguments[0]:6;!function(t,n){if(!(t instanceof n))throw new TypeError("Cannot call a class as a function")}(this,t),this.csBits=n,this.registry=["__reserved for background__"]}var n,e,r;return n=t,e=[{key:"register",value:function(t){if(this.registry.length>=Math.pow(2,24-this.csBits))return null;var n,e=this.registry.length,r=Ui(e,this.csBits),i=(n=e+(r<<24-this.csBits),"#".concat(Math.min(n,Math.pow(2,24)).toString(16).padStart(6,"0")));return this.registry.push(t),i}},{key:"lookup",value:function(t){var n,e,r,i,o="string"==typeof t?(n=ei(t).toRgb(),e=n.r,r=n.g,i=n.b,Ii(e,r,i)):Ii.apply(void 0,Ri(t));if(!o)return null;var a=o&Math.pow(2,24-this.csBits)-1,u=o>>24-this.csBits&Math.pow(2,this.csBits)-1;return Ui(a,this.csBits)!==u||a>=this.registry.length?null:this.registry[a]}}],e&&Ti(n.prototype,e),r&&Ti(n,r),Object.defineProperty(n,"prototype",{writable:!1}),t}();function Li(t,n,e){var r,i=1;function o(){var o,a,u=r.length,s=0,l=0,c=0;for(o=0;o=(i=(h+f)/2))?h=i:f=i,r=l,!(l=l[u=+a]))return r[u]=c,t;if(n===(o=+t._x.call(null,l.data)))return c.next=l,r?r[u]=c:t._root=c,t;do{r=r?r[u]=new Array(2):t._root=new Array(2),(a=n>=(i=(h+f)/2))?h=i:f=i}while((u=+a)==(s=+(o>=i)));return r[s]=l,r[u]=c,t}function Bi(t,n,e){this.node=t,this.x0=n,this.x1=e}function $i(t){return t[0]}function Hi(t,n){var e=new Vi(null==n?$i:n,NaN,NaN);return null==t?e:e.addAll(t)}function Vi(t,n,e){this._x=t,this._x0=n,this._x1=e,this._root=void 0}function Xi(t){for(var n={data:t.data},e=n;t=t.next;)e=e.next={data:t.data};return n}var Gi=Hi.prototype=Vi.prototype;function Yi(t,n,e,r){if(isNaN(n)||isNaN(e))return t;var i,o,a,u,s,l,c,h,f,d=t._root,p={data:r},g=t._x0,y=t._y0,v=t._x1,_=t._y1;if(!d)return t._root=p,t;for(;d.length;)if((l=n>=(o=(g+v)/2))?g=o:v=o,(c=e>=(a=(y+_)/2))?y=a:_=a,i=d,!(d=d[h=c<<1|l]))return i[h]=p,t;if(u=+t._x.call(null,d.data),s=+t._y.call(null,d.data),n===u&&e===s)return p.next=d,i?i[h]=p:t._root=p,t;do{i=i?i[h]=new Array(4):t._root=new Array(4),(l=n>=(o=(g+v)/2))?g=o:v=o,(c=e>=(a=(y+_)/2))?y=a:_=a}while((h=c<<1|l)==(f=(s>=a)<<1|u>=o));return i[f]=d,i[h]=p,t}function Wi(t,n,e,r,i){this.node=t,this.x0=n,this.y0=e,this.x1=r,this.y1=i}function Zi(t){return t[0]}function Qi(t){return t[1]}function Ki(t,n,e){var r=new Ji(null==n?Zi:n,null==e?Qi:e,NaN,NaN,NaN,NaN);return null==t?r:r.addAll(t)}function Ji(t,n,e,r,i,o){this._x=t,this._y=n,this._x0=e,this._y0=r,this._x1=i,this._y1=o,this._root=void 0}function to(t){for(var n={data:t.data},e=n;t=t.next;)e=e.next={data:t.data};return n}Gi.copy=function(){var t,n,e=new Vi(this._x,this._x0,this._x1),r=this._root;if(!r)return e;if(!r.length)return e._root=Xi(r),e;for(t=[{source:r,target:e._root=new Array(2)}];r=t.pop();)for(var i=0;i<2;++i)(n=r.source[i])&&(n.length?t.push({source:n,target:r.target[i]=new Array(2)}):r.target[i]=Xi(n));return e},Gi.add=function(t){const n=+this._x.call(null,t);return qi(this.cover(n),n,t)},Gi.addAll=function(t){Array.isArray(t)||(t=Array.from(t));const n=t.length,e=new Float64Array(n);let r=1/0,i=-1/0;for(let o,a=0;ai&&(i=o));if(r>i)return this;this.cover(r).cover(i);for(let r=0;rt||t>=e;)switch(i=+(ts||(i=o.x1)=h))&&(o=l[l.length-1],l[l.length-1]=l[l.length-1-a],l[l.length-1-a]=o)}else{var f=Math.abs(t-+this._x.call(null,c.data));f=(a=(h+f)/2))?h=a:f=a,n=c,!(c=c[s=+u]))return this;if(!c.length)break;n[s+1&1]&&(e=n,l=s)}for(;c.data!==t;)if(r=c,!(c=c.next))return this;return(i=c.next)&&delete c.next,r?(i?r.next=i:delete r.next,this):n?(i?n[s]=i:delete n[s],(c=n[0]||n[1])&&c===(n[1]||n[0])&&!c.length&&(e?e[l]=c:this._root=c),this):(this._root=i,this)},Gi.removeAll=function(t){for(var n=0,e=t.length;n=(a=(m+w)/2))?m=a:w=a,(d=e>=(u=(x+k)/2))?x=u:k=u,(p=r>=(s=(b+M)/2))?b=s:M=s,o=v,!(v=v[g=p<<2|d<<1|f]))return o[g]=_,t;if(l=+t._x.call(null,v.data),c=+t._y.call(null,v.data),h=+t._z.call(null,v.data),n===l&&e===c&&r===h)return _.next=v,o?o[g]=_:t._root=_,t;do{o=o?o[g]=new Array(8):t._root=new Array(8),(f=n>=(a=(m+w)/2))?m=a:w=a,(d=e>=(u=(x+k)/2))?x=u:k=u,(p=r>=(s=(b+M)/2))?b=s:M=s}while((g=p<<2|d<<1|f)==(y=(h>=s)<<2|(c>=u)<<1|l>=a));return o[y]=v,o[g]=_,t}function ro(t,n,e,r,i,o,a){this.node=t,this.x0=n,this.y0=e,this.z0=r,this.x1=i,this.y1=o,this.z1=a}function io(t){return t[0]}function oo(t){return t[1]}function ao(t){return t[2]}function uo(t,n,e,r){var i=new so(null==n?io:n,null==e?oo:e,null==r?ao:r,NaN,NaN,NaN,NaN,NaN,NaN);return null==t?i:i.addAll(t)}function so(t,n,e,r,i,o,a,u,s){this._x=t,this._y=n,this._z=e,this._x0=r,this._y0=i,this._z0=o,this._x1=a,this._y1=u,this._z1=s,this._root=void 0}function lo(t){for(var n={data:t.data},e=n;t=t.next;)e=e.next={data:t.data};return n}no.copy=function(){var t,n,e=new Ji(this._x,this._y,this._x0,this._y0,this._x1,this._y1),r=this._root;if(!r)return e;if(!r.length)return e._root=to(r),e;for(t=[{source:r,target:e._root=new Array(4)}];r=t.pop();)for(var i=0;i<4;++i)(n=r.source[i])&&(n.length?t.push({source:n,target:r.target[i]=new Array(4)}):r.target[i]=to(n));return e},no.add=function(t){const n=+this._x.call(null,t),e=+this._y.call(null,t);return Yi(this.cover(n,e),n,e,t)},no.addAll=function(t){var n,e,r,i,o=t.length,a=new Array(o),u=new Array(o),s=1/0,l=1/0,c=-1/0,h=-1/0;for(e=0;ec&&(c=r),ih&&(h=i));if(s>c||l>h)return this;for(this.cover(s,l).cover(c,h),e=0;et||t>=i||r>n||n>=o;)switch(u=(nf||(o=s.y0)>d||(a=s.x1)=v)<<1|t>=y)&&(s=p[p.length-1],p[p.length-1]=p[p.length-1-l],p[p.length-1-l]=s)}else{var _=t-+this._x.call(null,g.data),m=n-+this._y.call(null,g.data),x=_*_+m*m;if(x=(u=(p+y)/2))?p=u:y=u,(c=a>=(s=(g+v)/2))?g=s:v=s,n=d,!(d=d[h=c<<1|l]))return this;if(!d.length)break;(n[h+1&3]||n[h+2&3]||n[h+3&3])&&(e=n,f=h)}for(;d.data!==t;)if(r=d,!(d=d.next))return this;return(i=d.next)&&delete d.next,r?(i?r.next=i:delete r.next,this):n?(i?n[h]=i:delete n[h],(d=n[0]||n[1]||n[2]||n[3])&&d===(n[3]||n[2]||n[1]||n[0])&&!d.length&&(e?e[f]=d:this._root=d),this):(this._root=i,this)},no.removeAll=function(t){for(var n=0,e=t.length;n1&&(v=f.y+f.vy-c.y-c.vy||fo(u)),i>2&&(_=f.z+f.vz-c.z-c.vz||fo(u)),y*=d=((d=Math.sqrt(y*y+v*v+_*_))-e[g])/d*r*n[g],v*=d,_*=d,f.vx-=y*(p=a[g]),i>1&&(f.vy-=v*p),i>2&&(f.vz-=_*p),c.vx+=y*(p=1-p),i>1&&(c.vy+=v*p),i>2&&(c.vz+=_*p)}function d(){if(r){var i,u,l=r.length,c=t.length,h=new Map(r.map(((t,n)=>[s(t,n,r),t])));for(i=0,o=new Array(l);i"function"==typeof t))||Math.random,i=n.find((t=>[1,2,3].includes(t)))||2,d()},f.links=function(n){return arguments.length?(t=n,d(),f):t},f.id=function(t){return arguments.length?(s=t,f):s},f.iterations=function(t){return arguments.length?(h=+t,f):h},f.strength=function(t){return arguments.length?(l="function"==typeof t?t:ho(+t),p(),f):l},f.distance=function(t){return arguments.length?(c="function"==typeof t?t:ho(+t),g(),f):c},f}co.copy=function(){var t,n,e=new so(this._x,this._y,this._z,this._x0,this._y0,this._z0,this._x1,this._y1,this._z1),r=this._root;if(!r)return e;if(!r.length)return e._root=lo(r),e;for(t=[{source:r,target:e._root=new Array(8)}];r=t.pop();)for(var i=0;i<8;++i)(n=r.source[i])&&(n.length?t.push({source:n,target:r.target[i]=new Array(8)}):r.target[i]=lo(n));return e},co.add=function(t){const n=+this._x.call(null,t),e=+this._y.call(null,t),r=+this._z.call(null,t);return eo(this.cover(n,e,r),n,e,r,t)},co.addAll=function(t){Array.isArray(t)||(t=Array.from(t));const n=t.length,e=new Float64Array(n),r=new Float64Array(n),i=new Float64Array(n);let o=1/0,a=1/0,u=1/0,s=-1/0,l=-1/0,c=-1/0;for(let h,f,d,p,g=0;gs&&(s=f),dl&&(l=d),pc&&(c=p));if(o>s||a>l||u>c)return this;this.cover(o,a,u).cover(s,l,c);for(let o=0;ot||t>=a||i>n||n>=u||o>e||e>=s;)switch(c=(ey||(a=h.y0)>v||(u=h.z0)>_||(s=h.x1)=k)<<2|(n>=w)<<1|t>=b)&&(h=m[m.length-1],m[m.length-1]=m[m.length-1-f],m[m.length-1-f]=h)}else{var M=t-+this._x.call(null,x.data),z=n-+this._y.call(null,x.data),A=e-+this._z.call(null,x.data),S=M*M+z*z+A*A;if(S=(s=(v+x)/2))?v=s:x=s,(f=a>=(l=(_+b)/2))?_=l:b=l,(d=u>=(c=(m+w)/2))?m=c:w=c,n=y,!(y=y[p=d<<2|f<<1|h]))return this;if(!y.length)break;(n[p+1&7]||n[p+2&7]||n[p+3&7]||n[p+4&7]||n[p+5&7]||n[p+6&7]||n[p+7&7])&&(e=n,g=p)}for(;y.data!==t;)if(r=y,!(y=y.next))return this;return(i=y.next)&&delete y.next,r?(i?r.next=i:delete r.next,this):n?(i?n[p]=i:delete n[p],(y=n[0]||n[1]||n[2]||n[3]||n[4]||n[5]||n[6]||n[7])&&y===(n[7]||n[6]||n[5]||n[4]||n[3]||n[2]||n[1]||n[0])&&!y.length&&(e?e[g]=y:this._root=y),this):(this._root=i,this)},co.removeAll=function(t){for(var n=0,e=t.length;n(t=(vo*t+_o)%mo)/mo}();function d(){p(),h.call("tick",e),i1&&(null==c.fy?c.y+=c.vy*=s:(c.y=c.fy,c.vy=0)),r>2&&(null==c.fz?c.z+=c.vz*=s:(c.z=c.fz,c.vz=0));return e}function g(){for(var n,e=0,i=t.length;e1&&isNaN(n.y)||r>2&&isNaN(n.z)){var o=10*(r>2?Math.cbrt(.5+e):r>1?Math.sqrt(.5+e):e),a=e*ko,u=e*Mo;1===r?n.x=o:2===r?(n.x=o*Math.cos(a),n.y=o*Math.sin(a)):(n.x=o*Math.sin(a)*Math.cos(u),n.y=o*Math.cos(a),n.z=o*Math.sin(a)*Math.sin(u))}(isNaN(n.vx)||r>1&&isNaN(n.vy)||r>2&&isNaN(n.vz))&&(n.vx=0,r>1&&(n.vy=0),r>2&&(n.vz=0))}}function y(n){return n.initialize&&n.initialize(t,f,r),n}return null==t&&(t=[]),g(),e={tick:p,restart:function(){return c.restart(d),e},stop:function(){return c.stop(),e},numDimensions:function(t){return arguments.length?(r=Math.min(3,Math.max(1,Math.round(t))),l.forEach(y),e):r},nodes:function(n){return arguments.length?(t=n,g(),l.forEach(y),e):t},alpha:function(t){return arguments.length?(i=+t,e):i},alphaMin:function(t){return arguments.length?(o=+t,e):o},alphaDecay:function(t){return arguments.length?(a=+t,e):+a},alphaTarget:function(t){return arguments.length?(u=+t,e):u},velocityDecay:function(t){return arguments.length?(s=1-t,e):1-s},randomSource:function(t){return arguments.length?(f=t,l.forEach(y),e):f},force:function(t,n){return arguments.length>1?(null==n?l.delete(t):l.set(t,y(n)),e):l.get(t)},find:function(){var n,e,i,o,a,u,s=Array.prototype.slice.call(arguments),l=s.shift()||0,c=(r>1?s.shift():null)||0,h=(r>2?s.shift():null)||0,f=s.shift()||1/0,d=0,p=t.length;for(f*=f,d=0;d1?(h.on(t,n),e):h.on(t)}}}function Ao(){var t,n,e,r,i,o,a=ho(-30),u=1,s=1/0,l=.81;function c(r){var o,a=t.length,u=(1===n?Hi(t,xo):2===n?Ki(t,xo,bo):3===n?uo(t,xo,bo,wo):null).visitAfter(f);for(i=r,o=0;o1&&(t.y=a/c),n>2&&(t.z=u/c)}else{(e=t).x=e.data.x,n>1&&(e.y=e.data.y),n>2&&(e.z=e.data.z);do{l+=o[e.data.index]}while(e=e.next)}t.value=l}function d(t,a,c,h,f){if(!t.value)return!0;var d=[c,h,f][n-1],p=t.x-e.x,g=n>1?t.y-e.y:0,y=n>2?t.z-e.z:0,v=d-a,_=p*p+g*g+y*y;if(v*v/l<_)return _1&&0===g&&(_+=(g=fo(r))*g),n>2&&0===y&&(_+=(y=fo(r))*y),_1&&(e.vy+=g*t.value*i/_),n>2&&(e.vz+=y*t.value*i/_)),!0;if(!(t.length||_>=s)){(t.data!==e||t.next)&&(0===p&&(_+=(p=fo(r))*p),n>1&&0===g&&(_+=(g=fo(r))*g),n>2&&0===y&&(_+=(y=fo(r))*y),_1&&(e.vy+=g*v),n>2&&(e.vz+=y*v))}while(t=t.next)}}return c.initialize=function(e,...i){t=e,r=i.find((t=>"function"==typeof t))||Math.random,n=i.find((t=>[1,2,3].includes(t)))||2,h()},c.strength=function(t){return arguments.length?(a="function"==typeof t?t:ho(+t),h(),c):a},c.distanceMin=function(t){return arguments.length?(u=t*t,c):Math.sqrt(u)},c.distanceMax=function(t){return arguments.length?(s=t*t,c):Math.sqrt(s)},c.theta=function(t){return arguments.length?(l=t*t,c):Math.sqrt(l)},c}const{abs:So,cos:Co,sin:Eo,acos:Oo,atan2:No,sqrt:Po,pow:jo}=Math;function To(t){return t<0?-jo(-t,1/3):jo(t,1/3)}const Ro=Math.PI,Do=2*Ro,Io=Ro/2,Uo=Number.MAX_SAFE_INTEGER||9007199254740991,Fo=Number.MIN_SAFE_INTEGER||-9007199254740991,Lo={x:0,y:0,z:0},qo={Tvalues:[-.06405689286260563,.06405689286260563,-.1911188674736163,.1911188674736163,-.3150426796961634,.3150426796961634,-.4337935076260451,.4337935076260451,-.5454214713888396,.5454214713888396,-.6480936519369755,.6480936519369755,-.7401241915785544,.7401241915785544,-.820001985973903,.820001985973903,-.8864155270044011,.8864155270044011,-.9382745520027328,.9382745520027328,-.9747285559713095,.9747285559713095,-.9951872199970213,.9951872199970213],Cvalues:[.12793819534675216,.12793819534675216,.1258374563468283,.1258374563468283,.12167047292780339,.12167047292780339,.1155056680537256,.1155056680537256,.10744427011596563,.10744427011596563,.09761865210411388,.09761865210411388,.08619016153195327,.08619016153195327,.0733464814110803,.0733464814110803,.05929858491543678,.05929858491543678,.04427743881741981,.04427743881741981,.028531388628933663,.028531388628933663,.0123412297999872,.0123412297999872],arcfn:function(t,n){const e=n(t);let r=e.x*e.x+e.y*e.y;return void 0!==e.z&&(r+=e.z*e.z),Po(r)},compute:function(t,n,e){if(0===t)return n[0].t=0,n[0];const r=n.length-1;if(1===t)return n[r].t=1,n[r];const i=1-t;let o=n;if(0===r)return n[0].t=t,n[0];if(1===r){const n={x:i*o[0].x+t*o[1].x,y:i*o[0].y+t*o[1].y,t:t};return e&&(n.z=i*o[0].z+t*o[1].z),n}if(r<4){let n,a,u,s=i*i,l=t*t,c=0;2===r?(o=[o[0],o[1],o[2],Lo],n=s,a=i*t*2,u=l):3===r&&(n=s*i,a=s*t*3,u=i*l*3,c=t*l);const h={x:n*o[0].x+a*o[1].x+u*o[2].x+c*o[3].x,y:n*o[0].y+a*o[1].y+u*o[2].y+c*o[3].y,t:t};return e&&(h.z=n*o[0].z+a*o[1].z+u*o[2].z+c*o[3].z),h}const a=JSON.parse(JSON.stringify(n));for(;a.length>1;){for(let n=0;n1;i--,o--){const t=[];for(let e,i=0;io.x.min&&(n=o.x.min),e>o.y.min&&(e=o.y.min),r0&&(a.c1=n,a.c2=r,a.s1=t,a.s2=e,o.push(a))}))})),o},makeshape:function(t,n,e){const r=n.points.length,i=t.points.length,o=qo.makeline(n.points[r-1],t.points[0]),a=qo.makeline(t.points[i-1],n.points[0]),u={startcap:o,forward:t,back:n,endcap:a,bbox:qo.findbbox([o,t,n,a]),intersections:function(t){return qo.shapeintersections(u,u.bbox,t,t.bbox,e)}};return u},getminmax:function(t,n,e){if(!e)return{min:0,max:0};let r,i,o=Uo,a=Fo;-1===e.indexOf(0)&&(e=[0].concat(e)),-1===e.indexOf(1)&&e.push(1);for(let u=0,s=e.length;ua&&(a=i[n]);return{min:o,mid:(o+a)/2,max:a,size:a-o}},align:function(t,n){const e=n.p1.x,r=n.p1.y,i=-No(n.p2.y-r,n.p2.x-e);return t.map((function(t){return{x:(t.x-e)*Co(i)-(t.y-r)*Eo(i),y:(t.x-e)*Eo(i)+(t.y-r)*Co(i)}}))},roots:function(t,n){n=n||{p1:{x:0,y:0},p2:{x:1,y:0}};const e=t.length-1,r=qo.align(t,n),i=function(t){return 0<=t&&t<=1};if(2===e){const t=r[0].y,n=r[1].y,e=r[2].y,o=t-2*n+e;if(0!==o){const r=-Po(n*n-t*e),a=-t+n;return[-(r+a)/o,-(-r+a)/o].filter(i)}return n!==e&&0===o?[(2*n-e)/(2*n-2*e)].filter(i):[]}const o=r[0].y,a=r[1].y,u=r[2].y;let s=3*a-o-3*u+r[3].y,l=3*o-6*a+3*u,c=-3*o+3*a,h=o;if(qo.approximately(s,0)){if(qo.approximately(l,0))return qo.approximately(c,0)?[]:[-h/c].filter(i);const t=Po(c*c-4*l*h),n=2*l;return[(t-c)/n,(-c-t)/n].filter(i)}l/=s,c/=s,h/=s;const f=(3*c-l*l)/3,d=f/3,p=(2*l*l*l-9*l*c+27*h)/27,g=p/2,y=g*g+d*d*d;let v,_,m,x,b;if(y<0){const t=-f/3,n=Po(t*t*t),e=-p/(2*n),r=Oo(e<-1?-1:e>1?1:e),o=2*To(n);return m=o*Co(r/3)-l/3,x=o*Co((r+Do)/3)-l/3,b=o*Co((r+2*Do)/3)-l/3,[m,x,b].filter(i)}if(0===y)return v=g<0?To(-g):-To(g),m=2*v-l/3,x=-v-l/3,[m,x].filter(i);{const t=Po(y);return v=To(-g+t),_=To(g+t),[v-_-l/3].filter(i)}},droots:function(t){if(3===t.length){const n=t[0],e=t[1],r=t[2],i=n-2*e+r;if(0!==i){const t=-Po(e*e-n*r),o=-n+e;return[-(t+o)/i,-(-t+o)/i]}return e!==r&&0===i?[(2*e-r)/(2*(e-r))]:[]}if(2===t.length){const n=t[0],e=t[1];return n!==e?[n/(n-e)]:[]}return[]},curvature:function(t,n,e,r,i){let o,a,u,s,l=0,c=0;const h=qo.compute(t,n),f=qo.compute(t,e),d=h.x*h.x+h.y*h.y;if(r?(o=Po(jo(h.y*f.z-f.y*h.z,2)+jo(h.z*f.x-f.z*h.x,2)+jo(h.x*f.y-f.x*h.y,2)),a=jo(d+h.z*h.z,1.5)):(o=h.x*f.y-h.y*f.x,a=jo(d,1.5)),0===o||0===a)return{k:0,r:0};if(l=o/a,c=a/o,!i){const i=qo.curvature(t-.001,n,e,r,!0).k,o=qo.curvature(t+.001,n,e,r,!0).k;s=(o-l+(l-i))/2,u=(So(o-l)+So(l-i))/2}return{k:l,r:c,dk:s,adk:u}},inflections:function(t){if(t.length<4)return[];const n=qo.align(t,{p1:t[0],p2:t.slice(-1)[0]}),e=n[2].x*n[1].y,r=n[3].x*n[1].y,i=n[1].x*n[2].y,o=18*(-3*e+2*r+3*i-n[3].x*n[2].y),a=18*(3*e-r-3*i),u=18*(i-e);if(qo.approximately(o,0)){if(!qo.approximately(a,0)){let t=-u/a;if(0<=t&&t<=1)return[t]}return[]}const s=2*o;if(qo.approximately(s,0))return[];const l=a*a-4*o*u;if(l<0)return[];const c=Math.sqrt(l);return[(c-a)/s,-(a+c)/s].filter((function(t){return 0<=t&&t<=1}))},bboxoverlap:function(t,n){const e=["x","y"],r=e.length;for(let i,o,a,u,s=0;s=u)return!1;return!0},expandbox:function(t,n){n.x.mint.x.max&&(t.x.max=n.x.max),n.y.max>t.y.max&&(t.y.max=n.y.max),n.z&&n.z.max>t.z.max&&(t.z.max=n.z.max),t.x.mid=(t.x.min+t.x.max)/2,t.y.mid=(t.y.min+t.y.max)/2,t.z&&(t.z.mid=(t.z.min+t.z.max)/2),t.x.size=t.x.max-t.x.min,t.y.size=t.y.max-t.y.min,t.z&&(t.z.size=t.z.max-t.z.min)},pairiteration:function(t,n,e){const r=t.bbox(),i=n.bbox(),o=1e5,a=e||.5;if(r.x.size+r.y.sizek||k>M)&&(w+=Do),w>M&&(b=M,M=w,w=b)):M4){if(1!==arguments.length)throw new Error("Only new Bezier(point[]) is accepted for 4th and higher order curves");r=!0}}else if(6!==i&&8!==i&&9!==i&&12!==i&&1!==arguments.length)throw new Error("Only new Bezier(point[]) is accepted for 4th and higher order curves");const o=this._3d=!r&&(9===i||12===i)||t&&t[0]&&void 0!==t[0].z,a=this.points=[];for(let t=0,e=o?3:2;tt+$o(n.y)),0)0}length(){return qo.length(this.derivative.bind(this))}static getABC(t=2,n,e,r,i=.5){const o=qo.projectionratio(i,t),a=1-o,u={x:o*n.x+a*r.x,y:o*n.y+a*r.y},s=qo.abcratio(i,t);return{A:{x:e.x+(e.x-u.x)/s,y:e.y+(e.y-u.y)/s},B:e,C:u,S:n,E:r}}getABC(t,n){n=n||this.get(t);let e=this.points[0],r=this.points[this.order];return Qo.getABC(this.order,e,n,r,t)}getLUT(t){if(this.verify(),t=t||100,this._lut.length===t+1)return this._lut;this._lut=[],t++,this._lut=[];for(let n,e,r=0;r1?1:h,s=this.compute(h),s.t=h,s.d=l,s}get(t){return this.compute(t)}point(t){return this.points[t]}compute(t){return this.ratios?qo.computeWithRatios(t,this.points,this.ratios,this._3d):qo.compute(t,this.points,this._3d,this.ratios)}raise(){const t=this.points,n=[t[0]],e=t.length;for(let r,i,o=1;o1;){e=[];for(let o,a=0,u=n.length-1;a=0&&t<=1})),n=n.concat(t[e].sort(qo.numberSort))}.bind(this)),t.values=n.sort(qo.numberSort).filter((function(t,e){return n.indexOf(t)===e})),t}bbox(){const t=this.extrema(),n={};return this.dims.forEach(function(e){n[e]=qo.getminmax(this,e,t[e])}.bind(this)),n}overlaps(t){const n=this.bbox(),e=t.bbox();return qo.bboxoverlap(n,e)}offset(t,n){if(void 0!==n){const e=this.get(t),r=this.normal(t),i={c:e,n:r,x:e.x+r.x*n,y:e.y+r.y*n};return this._3d&&(i.z=e.z+r.z*n),i}if(this._linear){const n=this.normal(0),e=this.points.map((function(e){const r={x:e.x+t*n.x,y:e.y+t*n.y};return e.z&&n.z&&(r.z=e.z+t*n.z),r}));return[new Qo(e)]}return this.reduce().map((function(n){return n._linear?n.offset(t)[0]:n.scale(t)}))}simple(){if(3===this.order){const t=qo.angle(this.points[0],this.points[3],this.points[1]),n=qo.angle(this.points[0],this.points[3],this.points[2]);if(t>0&&n<0||t<0&&n>0)return!1}const t=this.normal(0),n=this.normal(1);let e=t.x*n.x+t.y*n.y;return this._3d&&(e+=t.z*n.z),$o(Yo(e))(1-i/r)*n+i/r*e));return new Qo(this.points.map(((n,e)=>({x:n.x+t.x*i[e],y:n.y+t.y*i[e]}))))}scale(t){const n=this.order;let e=!1;if("function"==typeof t&&(e=t),e&&2===n)return this.raise().scale(e);const r=this.clockwise,i=this.points;if(this._linear)return this.translate(this.normal(0),e?e(0):t,e?e(1):t);const o=e?e(0):t,a=e?e(1):t,u=[this.offset(0,10),this.offset(1,10)],s=[],l=qo.lli4(u[0],u[0].c,u[1],u[1].c);if(!l)throw new Error("cannot scale this curve. Try reducing it first.");return[0,1].forEach((function(t){const e=s[t*n]=qo.copy(i[t*n]);e.x+=(t?a:o)*u[t].n.x,e.y+=(t?a:o)*u[t].n.y})),e?([0,1].forEach((function(o){if(2!==n||!o){var a=i[o+1],u={x:a.x-l.x,y:a.y-l.y},c=e?e((o+1)/n):t;e&&!r&&(c=-c);var h=Wo(u.x*u.x+u.y*u.y);u.x/=h,u.y/=h,s[o+1]={x:a.x+c*u.x,y:a.y+c*u.y}}})),new Qo(s)):([0,1].forEach((t=>{if(2===n&&t)return;const e=s[t*n],r=this.derivative(t),o={x:e.x+r.x,y:e.y+r.y};s[t+1]=qo.lli4(e,o,l,i[t+1])})),new Qo(s))}outline(t,n,e,r){if(n=void 0===n?t:n,this._linear){const i=this.normal(0),o=this.points[0],a=this.points[this.points.length-1];let u,s,l;void 0===e&&(e=t,r=n),u={x:o.x+i.x*t,y:o.y+i.y*t},l={x:a.x+i.x*e,y:a.y+i.y*e},s={x:(u.x+l.x)/2,y:(u.y+l.y)/2};const c=[u,s,l];u={x:o.x-i.x*n,y:o.y-i.y*n},l={x:a.x-i.x*r,y:a.y-i.y*r},s={x:(u.x+l.x)/2,y:(u.y+l.y)/2};const h=[l,s,u],f=qo.makeline(h[2],c[0]),d=qo.makeline(c[2],h[0]),p=[f,new Qo(c),d,new Qo(h)];return new Bo(p)}const i=this.reduce(),o=i.length,a=[];let u,s=[],l=0,c=this.length();const h=void 0!==e&&void 0!==r;function f(t,n,e,r,i){return function(o){const a=r/e,u=(r+i)/e,s=n-t;return qo.map(o,0,1,t+a*s,t+u*s)}}i.forEach((function(i){const o=i.length();h?(a.push(i.scale(f(t,e,c,l,o))),s.push(i.scale(f(-n,-r,c,l,o)))):(a.push(i.scale(t)),s.push(i.scale(-n))),l+=o})),s=s.map((function(t){return u=t.points,u[3]?t.points=[u[3],u[2],u[1],u[0]]:t.points=[u[2],u[1],u[0]],t})).reverse();const d=a[0].points[0],p=a[o-1].points[a[o-1].points.length-1],g=s[o-1].points[s[o-1].points.length-1],y=s[0].points[0],v=qo.makeline(g,d),_=qo.makeline(p,y),m=[v].concat(a).concat([_]).concat(s);return new Bo(m)}outlineshapes(t,n,e){n=n||t;const r=this.outline(t,n).curves,i=[];for(let t=1,n=r.length;t1,o.endcap.virtual=t{var o=this.get(t);return qo.between(o.x,n,r)&&qo.between(o.y,e,i)}))}selfintersects(t){const n=this.reduce(),e=n.length-2,r=[];for(let i,o,a,u=0;u0&&(i=i.concat(n))})),i}arcs(t){return t=t||.5,this._iterate(t,[])}_error(t,n,e,r){const i=(r-e)/4,o=this.get(e+i),a=this.get(r-i),u=qo.dist(t,n),s=qo.dist(t,o),l=qo.dist(t,a);return $o(s-u)+$o(l-u)}_iterate(t,n){let e,r=0,i=1;do{e=0,i=1;let o,a,u,s,l,c=this.get(r),h=!1,f=!1,d=i,p=1;do{if(f=h,s=u,d=(r+i)/2,o=this.get(d),a=this.get(i),u=qo.getccenter(c,o,a),u.interval={start:r,end:i},h=this._error(u,c,r,i)<=t,l=f&&!h,l||(p=i),h){if(i>=1){if(u.interval.end=p=1,s=u,i>1){let t={x:u.x+u.r*Xo(u.e),y:u.y+u.r*Go(u.e)};u.e+=qo.angle({x:u.x,y:u.y},t,this.get(1))}break}i+=(i-r)/2}else i=d}while(!l&&e++<100);if(e>=100)break;s=s||u,n.push(s),r=p}while(i<1);return n}}function Ko(t,n){if(null==t)return{};var e,r,i=function(t,n){if(null==t)return{};var e,r,i={},o=Object.keys(t);for(r=0;r=0||(i[e]=t[e]);return i}(t,n);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(t);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(t,e)&&(i[e]=t[e])}return i}function Jo(t,n){return function(t){if(Array.isArray(t))return t}(t)||function(t,n){var e=null==t?null:"undefined"!=typeof Symbol&&t[Symbol.iterator]||t["@@iterator"];if(null!=e){var r,i,o,a,u=[],s=!0,l=!1;try{if(o=(e=e.call(t)).next,0===n){if(Object(e)!==e)return;s=!1}else for(;!(s=(r=o.call(e)).done)&&(u.push(r.value),u.length!==n);s=!0);}catch(t){l=!0,i=t}finally{try{if(!s&&null!=e.return&&(a=e.return(),Object(a)!==a))return}finally{if(l)throw i}}return u}}(t,n)||na(t,n)||function(){throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}()}function ta(t){return function(t){if(Array.isArray(t))return ea(t)}(t)||function(t){if("undefined"!=typeof Symbol&&null!=t[Symbol.iterator]||null!=t["@@iterator"])return Array.from(t)}(t)||na(t)||function(){throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}()}function na(t,n){if(t){if("string"==typeof t)return ea(t,n);var e=Object.prototype.toString.call(t).slice(8,-1);return"Object"===e&&t.constructor&&(e=t.constructor.name),"Map"===e||"Set"===e?Array.from(t):"Arguments"===e||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(e)?ea(t,n):void 0}}function ea(t,n){(null==n||n>t.length)&&(n=t.length);for(var e=0,r=new Array(n);et.cooldownTicks||new Date-t.startTickTime>t.cooldownTime||t.d3AlphaMin>0&&t.forceLayout.alpha()0){var a=Math.atan2(r.y-e.y,r.x-e.x),u=i*n,s={x:(e.x+r.x)/2+u*Math.cos(a-Math.PI/2),y:(e.y+r.y)/2+u*Math.sin(a-Math.PI/2)};t.__controlPoints=[s.x,s.y]}else{var l=70*n;t.__controlPoints=[r.x,r.y-l,r.x+l,r.y]}}));var f=[],d=[],p=h;if(t.linkCanvasObject){var g=[],y=[];h.forEach((function(t){return({before:f,after:d,replace:g}[a(t)]||y).push(t)})),p=[].concat(s(f),d,y),f=f.concat(g)}l.save(),f.forEach((function(n){return t.linkCanvasObject(n,l,t.globalScale)})),l.restore();var v=function(){var t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:[],n=arguments.length>1&&void 0!==arguments[1]?arguments[1]:[],e=!(arguments.length>2&&void 0!==arguments[2])||arguments[2],r=arguments.length>3&&void 0!==arguments[3]&&arguments[3],i=(n instanceof Array?n.length?n:[void 0]:[n]).map((function(t){return{keyAccessor:t,isProp:!(t instanceof Function)}})),o=t.reduce((function(t,n){var r=t,o=n;return i.forEach((function(t,n){var a,u=t.keyAccessor;if(t.isProp){var s=o,l=s[u],c=Ko(s,[u].map(ra));a=l,o=c}else a=u(o,n);n+11&&void 0!==arguments[1]?arguments[1]:1;r===i.length?Object.keys(n).forEach((function(t){return n[t]=e(n[t])})):Object.values(n).forEach((function(n){return t(n,r+1)}))}(o);var a=o;return r&&(a=[],function t(n){var e=arguments.length>1&&void 0!==arguments[1]?arguments[1]:[];e.length===i.length?a.push({keys:e,vals:n}):Object.entries(n).forEach((function(n){var r=Jo(n,2),i=r[0],o=r[1];return t(o,[].concat(ta(e),[i]))}))}(o),n instanceof Array&&0===n.length&&1===a.length&&(a[0].keys=[])),a}(p,[e,r,i]);l.save(),Object.entries(v).forEach((function(n){var e=u(n,2),r=e[0],o=e[1],a=r&&"undefined"!==r?r:"rgba(0,0,0,0.15)";Object.entries(o).forEach((function(n){var e=u(n,2),r=e[0],o=e[1],h=(r||1)/t.globalScale+c;Object.entries(o).forEach((function(t){var n=u(t,2);n[0];var e=n[1],r=i(e[0]);l.beginPath(),e.forEach((function(t){var n=t.source,e=t.target;if(n&&e&&n.hasOwnProperty("x")&&e.hasOwnProperty("x")){l.moveTo(n.x,n.y);var r=t.__controlPoints;r?l[2===r.length?"quadraticCurveTo":"bezierCurveTo"].apply(l,s(r).concat([e.x,e.y])):l.lineTo(e.x,e.y)}})),l.strokeStyle=a,l.lineWidth=h,l.setLineDash(r||[]),l.stroke()}))}))})),l.restore(),l.save(),d.forEach((function(n){return t.linkCanvasObject(n,l,t.globalScale)})),l.restore()}(),!t.isShadow&&(n=Kr(t.linkDirectionalArrowLength),e=Kr(t.linkDirectionalArrowRelPos),r=Kr(t.linkVisibility),i=Kr(t.linkDirectionalArrowColor||t.linkColor),o=Kr(t.nodeVal),(l=t.ctx).save(),t.graphData.links.filter(r).forEach((function(r){var u=n(r);if(u&&!(u<0)){var c=r.source,h=r.target;if(c&&h&&c.hasOwnProperty("x")&&h.hasOwnProperty("x")){var f=Math.sqrt(Math.max(0,o(c)||1))*t.nodeRelSize,d=Math.sqrt(Math.max(0,o(h)||1))*t.nodeRelSize,p=Math.min(1,Math.max(0,e(r))),g=i(r)||"rgba(0,0,0,0.28)",y=u/1.6/2,v=r.__controlPoints&&a(Qo,[c.x,c.y].concat(s(r.__controlPoints),[h.x,h.y])),_=v?function(t){return v.get(t)}:function(t){return{x:c.x+(h.x-c.x)*t||0,y:c.y+(h.y-c.y)*t||0}},m=v?v.length():Math.sqrt(Math.pow(h.x-c.x,2)+Math.pow(h.y-c.y,2)),x=f+u+(m-f-d-u)*p,b=_(x/m),w=_((x-u)/m),k=_((x-.8*u)/m),M=Math.atan2(b.y-w.y,b.x-w.x)-Math.PI/2;l.beginPath(),l.moveTo(b.x,b.y),l.lineTo(w.x+y*Math.cos(M),w.y+y*Math.sin(M)),l.lineTo(k.x,k.y),l.lineTo(w.x-y*Math.cos(M),w.y-y*Math.sin(M)),l.fillStyle=g,l.fill()}}})),l.restore()),!t.isShadow&&function(){var n=Kr(t.linkDirectionalParticles),e=Kr(t.linkDirectionalParticleSpeed),r=Kr(t.linkDirectionalParticleWidth),i=Kr(t.linkVisibility),o=Kr(t.linkDirectionalParticleColor||t.linkColor),u=t.ctx;u.save(),t.graphData.links.filter(i).forEach((function(i){var l=n(i);if(i.hasOwnProperty("__photons")&&i.__photons.length){var c=i.source,h=i.target;if(c&&h&&c.hasOwnProperty("x")&&h.hasOwnProperty("x")){var f=e(i),d=i.__photons||[],p=Math.max(0,r(i)/2)/Math.sqrt(t.globalScale),g=o(i)||"rgba(0,0,0,0.28)";u.fillStyle=g;var y=i.__controlPoints?a(Qo,[c.x,c.y].concat(s(i.__controlPoints),[h.x,h.y])):null,v=0,_=!1;d.forEach((function(t){var n=!!t.__singleHop;if(t.hasOwnProperty("__progressRatio")||(t.__progressRatio=n?0:v/l),!n&&v++,t.__progressRatio+=f,t.__progressRatio>=1){if(n)return void(_=!0);t.__progressRatio=t.__progressRatio%1}var e=t.__progressRatio,r=y?y.get(e):{x:c.x+(h.x-c.x)*e||0,y:c.y+(h.y-c.y)*e||0};u.beginPath(),u.arc(r.x,r.y,p,0,2*Math.PI,!1),u.fill()})),_&&(i.__photons=i.__photons.filter((function(t){return!t.__singleHop||t.__progressRatio<=1})))}}})),u.restore()}(),function(){var n=Kr(t.nodeVisibility),e=Kr(t.nodeVal),r=Kr(t.nodeColor),i=Kr(t.nodeCanvasObjectMode),o=t.ctx,a=t.isShadow/t.globalScale,u=t.graphData.nodes.filter(n);o.save(),u.forEach((function(n){var u=i(n);if(!t.nodeCanvasObject||"before"!==u&&"replace"!==u||(t.nodeCanvasObject(n,o,t.globalScale),"replace"!==u)){var s=Math.sqrt(Math.max(0,e(n)||1))*t.nodeRelSize+a;o.beginPath(),o.arc(n.x,n.y,s,0,2*Math.PI,!1),o.fillStyle=r(n)||"rgba(31, 120, 180, 0.92)",o.fill(),t.nodeCanvasObject&&"after"===u&&t.nodeCanvasObject(n,t.ctx,t.globalScale)}else o.restore()})),o.restore()}(),this},emitParticle:function(t,n){return n&&(!n.__photons&&(n.__photons=[]),n.__photons.push({__singleHop:!0})),this}},stateInit:function(){return{forceLayout:zo().force("link",yo()).force("charge",Ao()).force("center",Li()).force("dagRadial",null).stop(),engineRunning:!1}},init:function(t,n){n.ctx=t},update:function(t){t.engineRunning=!1,t.onUpdate(),null!==t.nodeAutoColorBy&&sa(t.graphData.nodes,Kr(t.nodeAutoColorBy),t.nodeColor),null!==t.linkAutoColorBy&&sa(t.graphData.links,Kr(t.linkAutoColorBy),t.linkColor),t.graphData.links.forEach((function(n){n.source=n[t.linkSource],n.target=n[t.linkTarget]})),t.forceLayout.stop().alpha(1).nodes(t.graphData.nodes);var n=t.forceLayout.force("link");n&&n.id((function(n){return n[t.nodeId]})).links(t.graphData.links);var e=t.dagMode&&function(t,n){var e=t.nodes,o=t.links,a=arguments.length>2&&void 0!==arguments[2]?arguments[2]:{},l=a.nodeFilter,c=void 0===l?function(){return!0}:l,h=a.onLoopError,f=void 0===h?function(t){throw"Invalid DAG structure! Found cycle in node path: ".concat(t.join(" -> "),".")}:h,d={};e.forEach((function(t){return d[n(t)]={data:t,out:[],depth:-1,skip:!c(t)}})),o.forEach((function(t){var e=t.source,i=t.target,o=l(e),a=l(i);if(!d.hasOwnProperty(o))throw"Missing source node with id: ".concat(o);if(!d.hasOwnProperty(a))throw"Missing target node with id: ".concat(a);var u=d[o],s=d[a];function l(t){return"object"===r(t)?n(t):t}u.out.push(s)}));var p=[];return function t(e){for(var r=arguments.length>1&&void 0!==arguments[1]?arguments[1]:[],i=arguments.length>2&&void 0!==arguments[2]?arguments[2]:0,o=function(){var o=e[a];if(-1!==r.indexOf(o)){var u=[].concat(s(r.slice(r.indexOf(o))),[o]).map((function(t){return n(t.data)}));return p.some((function(t){return t.length===u.length&&t.every((function(t,n){return t===u[n]}))}))||(p.push(u),f(u)),1}i>o.depth&&(o.depth=i,t(o.out,[].concat(s(r),[o]),i+(o.skip?0:1)))},a=0,u=e.length;a1&&(c.vy+=f*g),o>2&&(c.vz+=d*g)}}function c(){if(i){var n,e=i.length;for(a=new Array(e),u=new Array(e),n=0;n[1,2,3].includes(t)))||2,c()},l.strength=function(t){return arguments.length?(s="function"==typeof t?t:ho(+t),c(),l):s},l.radius=function(n){return arguments.length?(t="function"==typeof n?n:ho(+n),c(),l):t},l.x=function(t){return arguments.length?(n=+t,l):n},l.y=function(t){return arguments.length?(e=+t,l):e},l.z=function(t){return arguments.length?(r=+t,l):r},l}((function(n){var r=e[n[t.nodeId]]||-1;return("radialin"===t.dagMode?o-r:r)*a})).strength((function(n){return t.dagNodeFilter(n)?1:0})):null);for(var f=0;f0&&t.forceLayout.alpha()1?r-1:0),o=1;o1&&void 0!==arguments[1]?arguments[1]:0,e=arguments.length>2&&void 0!==arguments[2]?arguments[2]:10,r=arguments.length,i=new Array(r>3?r-3:0),o=3;o1&&void 0!==arguments[1]?arguments[1]:function(){return!0},e=Kr(t.nodeVal),r=function(n){return Math.sqrt(Math.max(0,e(n)||1))*t.nodeRelSize},i=t.graphData.nodes.filter(n).map((function(t){return{x:t.x,y:t.y,r:r(t)}}));return i.length?{x:[ur(i,(function(t){return t.x-t.r})),ar(i,(function(t){return t.x+t.r}))],y:[ur(i,(function(t){return t.y-t.r})),ar(i,(function(t){return t.y+t.r}))]}:null},pauseAnimation:function(t){return t.animationFrameRequestId&&(cancelAnimationFrame(t.animationFrameRequestId),t.animationFrameRequestId=null),this},resumeAnimation:function(t){return t.animationFrameRequestId||this._animationCycle(),this},_destructor:function(){this.pauseAnimation(),this.graphData({nodes:[],links:[]})}},ya),stateInit:function(){return{lastSetZoom:1,zoom:er(),forceGraph:new ha,shadowGraph:(new ha).cooldownTicks(0).nodeColor("__indexColor").linkColor("__indexColor").isShadow(!0),colorTracker:new Fi}},init:function(t,n){var r=this;t.innerHTML="";var i=document.createElement("div");i.classList.add("force-graph-container"),i.style.position="relative",t.appendChild(i),n.canvas=document.createElement("canvas"),n.backgroundColor&&(n.canvas.style.background=n.backgroundColor),i.appendChild(n.canvas),n.shadowCanvas=document.createElement("canvas");var o=n.canvas.getContext("2d"),a=n.shadowCanvas.getContext("2d",{willReadFrequently:!0}),u={x:-1e12,y:-1e12},s=function(){var t=null,e=window.devicePixelRatio,r=u.x>0&&u.y>0?a.getImageData(u.x*e,u.y*e,1,1):null;return r&&(t=n.colorTracker.lookup(r.data)),t};kt(n.canvas).call(function(){var t,n,e,r,i=Ut,o=Ft,a=Lt,u=qt,s={},l=At("start","drag","end"),c=0,h=0;function f(t){t.on("mousedown.drag",d).filter(u).on("touchstart.drag",y).on("touchmove.drag",v,Ot).on("touchend.drag touchcancel.drag",_).style("touch-action","none").style("-webkit-tap-highlight-color","rgba(0,0,0,0)")}function d(a,u){if(!r&&i.call(this,a,u)){var s=m(this,o.call(this,a,u),a,u,"mouse");s&&(kt(a.view).on("mousemove.drag",p,Nt).on("mouseup.drag",g,Nt),Tt(a.view),Pt(a),e=!1,t=a.clientX,n=a.clientY,s("start",a))}}function p(r){if(jt(r),!e){var i=r.clientX-t,o=r.clientY-n;e=i*i+o*o>h}s.mouse("drag",r)}function g(t){kt(t.view).on("mousemove.drag mouseup.drag",null),Rt(t.view,e),jt(t),s.mouse("end",t)}function y(t,n){if(i.call(this,t,n)){var e,r,a=t.changedTouches,u=o.call(this,t,n),s=a.length;for(e=0;e0||n.isPointerPressed)&&("touch"!==e.pointerType||void 0===e.movementX||[e.movementX,e.movementY].some((function(t){return Math.abs(t)>1})))&&(n.isPointerDragging=!0);var r,o,a,s=(r=i.getBoundingClientRect(),o=window.pageXOffset||document.documentElement.scrollLeft,a=window.pageYOffset||document.documentElement.scrollTop,{top:r.top+a,left:r.left+o});u.x=e.pageX-s.left,u.y=e.pageY-s.top,l.style.top="".concat(u.y,"px"),l.style.left="".concat(u.x,"px"),l.style.transform="translate(-".concat(u.x/n.width*100,"%, ").concat(n.height-u.y<100?"calc(-100% - 8px)":"21px",")")}),{passive:!0})})),i.addEventListener("pointerup",(function(t){if(n.isPointerPressed=!1,n.isPointerDragging)n.isPointerDragging=!1;else{var e=[t,n.pointerDownEvent];requestAnimationFrame((function(){if(0===t.button)if(n.hoverObj){var r=n["on".concat(n.hoverObj.type,"Click")];r&&r.apply(void 0,[n.hoverObj.d].concat(e))}else n.onBackgroundClick&&n.onBackgroundClick.apply(n,e);if(2===t.button)if(n.hoverObj){var i=n["on".concat(n.hoverObj.type,"RightClick")];i&&i.apply(void 0,[n.hoverObj.d].concat(e))}else n.onBackgroundRightClick&&n.onBackgroundRightClick.apply(n,e)}))}}),{passive:!0}),i.addEventListener("contextmenu",(function(t){return!(n.onBackgroundRightClick||n.onNodeRightClick||n.onLinkRightClick)||(t.preventDefault(),!1)})),n.forceGraph(o),n.shadowGraph(a);var c=function(t,n,e){var r=!0,i=!0;if("function"!=typeof t)throw new TypeError("Expected a function");return zr(e)&&(r="leading"in e?!!e.leading:r,i="trailing"in e?!!e.trailing:i),Dr(t,n,{leading:r,maxWait:n,trailing:i})}((function(){ma(a,n.width,n.height),n.shadowGraph.linkWidth((function(t){return Kr(n.linkWidth)(t)+n.linkHoverPrecision}));var t=Ge(n.canvas);n.shadowGraph.globalScale(t.k).tickFrame()}),800);n.flushShadowCanvas=c.flush,(this._animationCycle=function t(){var e=!n.autoPauseRedraw||!!n.needsRedraw||n.forceGraph.isEngineRunning()||n.graphData.links.some((function(t){return t.__photons&&t.__photons.length}));if(n.needsRedraw=!1,n.enablePointerInteraction){var r=n.isPointerDragging?null:s();if(r!==n.hoverObj){var i=n.hoverObj,a=i?i.type:null,u=r?r.type:null;if(a&&a!==u){var h=n["on".concat(a,"Hover")];h&&h(null,i.d)}if(u){var f=n["on".concat(u,"Hover")];f&&f(r.d,a===u?i.d:null)}var d=r&&Kr(n["".concat(r.type.toLowerCase(),"Label")])(r.d)||"";l.style.visibility=d?"visible":"hidden",l.innerHTML=d,n.canvas.classList[r&&n["on".concat(u,"Click")]||!r&&n.onBackgroundClick?"add":"remove"]("clickable"),n.hoverObj=r}e&&c()}if(e){ma(o,n.width,n.height);var p=Ge(n.canvas).k;n.onRenderFramePre&&n.onRenderFramePre(o,p),n.forceGraph.globalScale(p).tickFrame(),n.onRenderFramePost&&n.onRenderFramePost(o,p)}Vr(),n.animationFrameRequestId=requestAnimationFrame(t)})()},update:function(t){}});return xa})); diff --git a/resource/web/js/jquery-1.11.3.min.js b/hal-core/resources/web/js/lib/jquery-1.11.3.min.js similarity index 100% rename from resource/web/js/jquery-1.11.3.min.js rename to hal-core/resources/web/js/lib/jquery-1.11.3.min.js diff --git a/resource/web/js/jquery.filer.js b/hal-core/resources/web/js/lib/jquery.filer.js old mode 100755 new mode 100644 similarity index 100% rename from resource/web/js/jquery.filer.js rename to hal-core/resources/web/js/lib/jquery.filer.js diff --git a/resource/web/js/jquery.filer.min.js b/hal-core/resources/web/js/lib/jquery.filer.min.js old mode 100755 new mode 100644 similarity index 100% rename from resource/web/js/jquery.filer.min.js rename to hal-core/resources/web/js/lib/jquery.filer.min.js diff --git a/hal-core/resources/web/js/lib/moment.LICENSE.txt b/hal-core/resources/web/js/lib/moment.LICENSE.txt new file mode 100644 index 00000000..8618b733 --- /dev/null +++ b/hal-core/resources/web/js/lib/moment.LICENSE.txt @@ -0,0 +1,22 @@ +Copyright (c) JS Foundation and other contributors + +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. diff --git a/resource/web/js/moment.js b/hal-core/resources/web/js/lib/moment.js old mode 100755 new mode 100644 similarity index 100% rename from resource/web/js/moment.js rename to hal-core/resources/web/js/lib/moment.js diff --git a/hal-core/resources/web/js/lib/svg.LICENSE b/hal-core/resources/web/js/lib/svg.LICENSE new file mode 100644 index 00000000..41b1b108 --- /dev/null +++ b/hal-core/resources/web/js/lib/svg.LICENSE @@ -0,0 +1,21 @@ +Copyright (c) 2012-2018 Wout Fierens +https://svgdotjs.github.io/ + +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. diff --git a/hal-core/resources/web/js/lib/svg.draggable.LICENSE.txt b/hal-core/resources/web/js/lib/svg.draggable.LICENSE.txt new file mode 100644 index 00000000..83a83e25 --- /dev/null +++ b/hal-core/resources/web/js/lib/svg.draggable.LICENSE.txt @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2018 Ulrich-Matthias + +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. diff --git a/resource/web/js/svg.draggable.js b/hal-core/resources/web/js/lib/svg.draggable.js old mode 100755 new mode 100644 similarity index 79% rename from resource/web/js/svg.draggable.js rename to hal-core/resources/web/js/lib/svg.draggable.js index f106b4da..dda3807f --- a/resource/web/js/svg.draggable.js +++ b/hal-core/resources/web/js/lib/svg.draggable.js @@ -1,6 +1,6 @@ -/*! svg.draggable.js - v2.2.0 - 2016-05-21 -* https://github.com/wout/svg.draggable.js -* Copyright (c) 2016 Wout Fierens; Licensed MIT */ +/*! svg.draggable.js - v2.2.2 - 2019-01-08 +* https://github.com/svgdotjs/svg.draggable.js +* Copyright (c) 2019 Wout Fierens; Licensed MIT */ ;(function() { // creates handler, saves it @@ -23,18 +23,18 @@ DragHandler.prototype.transformPoint = function(event, offset){ event = event || window.event var touches = event.changedTouches && event.changedTouches[0] || event - this.p.x = touches.pageX - (offset || 0) - this.p.y = touches.pageY + this.p.x = touches.clientX - (offset || 0) + this.p.y = touches.clientY return this.p.matrixTransform(this.m) } - + // gets elements bounding box with special handling of groups, nested and use DragHandler.prototype.getBBox = function(){ var box = this.el.bbox() if(this.el instanceof SVG.Nested) box = this.el.rbox() - + if (this.el instanceof SVG.G || this.el instanceof SVG.Use || this.el instanceof SVG.Nested) { box.x = this.el.x() box.y = this.el.y() @@ -52,11 +52,18 @@ return } } - + var _this = this // fire beforedrag event this.el.fire('beforedrag', { event: e, handler: this }) + if(this.el.event().defaultPrevented) return; + + // prevent browser drag behavior as soon as possible + e.preventDefault(); + + // prevent propagation to a parent that might also have dragging enabled + e.stopPropagation(); // search for parent on the fly to make sure we can call // draggable() even when element is not in the dom currently @@ -67,13 +74,13 @@ this.m = this.el.node.getScreenCTM().inverse() var box = this.getBBox() - + var anchorOffset; - + // fix text-anchor in text-element (#37) if(this.el instanceof SVG.Text){ anchorOffset = this.el.node.getComputedTextLength(); - + switch(this.el.attr('text-anchor')){ case 'middle': anchorOffset /= 2; @@ -83,13 +90,14 @@ break; } } - + this.startPoints = { // We take absolute coordinates since we are just using a delta here point: this.transformPoint(e, anchorOffset), - box: box + box: box, + transform: this.el.transform() } - + // add drag and end events to window SVG.on(window, 'mousemove.drag', function(e){ _this.drag(e) }) SVG.on(window, 'touchmove.drag', function(e){ _this.drag(e) }) @@ -98,12 +106,6 @@ // fire dragstart event this.el.fire('dragstart', {event: e, p: this.startPoints.point, m: this.m, handler: this}) - - // prevent browser drag behavior - e.preventDefault() - - // prevent propagation to a parent that might also have dragging enabled - e.stopPropagation(); } // while dragging @@ -114,20 +116,17 @@ , x = this.startPoints.box.x + p.x - this.startPoints.point.x , y = this.startPoints.box.y + p.y - this.startPoints.point.y , c = this.constraint + , gx = p.x - this.startPoints.point.x + , gy = p.y - this.startPoints.point.y - var event = new CustomEvent('dragmove', { - detail: { - event: e - , p: p - , m: this.m - , handler: this - } - , cancelable: true + this.el.fire('dragmove', { + event: e + , p: p + , m: this.m + , handler: this }) - - this.el.fire(event) - - if(event.defaultPrevented) return p + + if(this.el.event().defaultPrevented) return p // move the element to its new position, if possible by constraint if (typeof c == 'function') { @@ -158,18 +157,33 @@ } else if (typeof c == 'object') { // keep element within constrained box - if (c.minX != null && x < c.minX) + if (c.minX != null && x < c.minX) { x = c.minX - else if (c.maxX != null && x > c.maxX - box.width){ + gx = x - this.startPoints.box.x + } else if (c.maxX != null && x > c.maxX - box.width) { x = c.maxX - box.width - }if (c.minY != null && y < c.minY) + gx = x - this.startPoints.box.x + } if (c.minY != null && y < c.minY) { y = c.minY - else if (c.maxY != null && y > c.maxY - box.height) + gy = y - this.startPoints.box.y + } else if (c.maxY != null && y > c.maxY - box.height) { y = c.maxY - box.height + gy = y - this.startPoints.box.y + } - this.el.move(x, y) + if (c.snapToGrid != null) { + x = x - (x % c.snapToGrid) + y = y - (y % c.snapToGrid) + gx = gx - (gx % c.snapToGrid) + gy = gy - (gy % c.snapToGrid) + } + + if(this.el instanceof SVG.G) + this.el.matrix(this.startPoints.transform).transform({x:gx, y: gy}, true) + else + this.el.move(x, y) } - + // so we can use it in the end-method, too return p } diff --git a/hal-core/resources/web/js/lib/svg.draggable.min.js b/hal-core/resources/web/js/lib/svg.draggable.min.js new file mode 100644 index 00000000..8381fccd --- /dev/null +++ b/hal-core/resources/web/js/lib/svg.draggable.min.js @@ -0,0 +1,4 @@ +/*! svg.draggable.js - v2.2.2 - 2019-01-08 +* https://github.com/svgdotjs/svg.draggable.js +* Copyright (c) 2019 Wout Fierens; Licensed MIT */ +(function(){function a(a){a.remember("_draggable",this),this.el=a}a.prototype.init=function(a,b){var c=this;this.constraint=a,this.value=b,this.el.on("mousedown.drag",function(a){c.start(a)}),this.el.on("touchstart.drag",function(a){c.start(a)})},a.prototype.transformPoint=function(a,b){a=a||window.event;var c=a.changedTouches&&a.changedTouches[0]||a;return this.p.x=c.clientX-(b||0),this.p.y=c.clientY,this.p.matrixTransform(this.m)},a.prototype.getBBox=function(){var a=this.el.bbox();return this.el instanceof SVG.Nested&&(a=this.el.rbox()),(this.el instanceof SVG.G||this.el instanceof SVG.Use||this.el instanceof SVG.Nested)&&(a.x=this.el.x(),a.y=this.el.y()),a},a.prototype.start=function(a){if("click"!=a.type&&"mousedown"!=a.type&&"mousemove"!=a.type||1==(a.which||a.buttons)){var b=this;if(this.el.fire("beforedrag",{event:a,handler:this}),!this.el.event().defaultPrevented){a.preventDefault(),a.stopPropagation(),this.parent=this.parent||this.el.parent(SVG.Nested)||this.el.parent(SVG.Doc),this.p=this.parent.node.createSVGPoint(),this.m=this.el.node.getScreenCTM().inverse();var c,d=this.getBBox();if(this.el instanceof SVG.Text)switch(c=this.el.node.getComputedTextLength(),this.el.attr("text-anchor")){case"middle":c/=2;break;case"start":c=0}this.startPoints={point:this.transformPoint(a,c),box:d,transform:this.el.transform()},SVG.on(window,"mousemove.drag",function(a){b.drag(a)}),SVG.on(window,"touchmove.drag",function(a){b.drag(a)}),SVG.on(window,"mouseup.drag",function(a){b.end(a)}),SVG.on(window,"touchend.drag",function(a){b.end(a)}),this.el.fire("dragstart",{event:a,p:this.startPoints.point,m:this.m,handler:this})}}},a.prototype.drag=function(a){var b=this.getBBox(),c=this.transformPoint(a),d=this.startPoints.box.x+c.x-this.startPoints.point.x,e=this.startPoints.box.y+c.y-this.startPoints.point.y,f=this.constraint,g=c.x-this.startPoints.point.x,h=c.y-this.startPoints.point.y;if(this.el.fire("dragmove",{event:a,p:c,m:this.m,handler:this}),this.el.event().defaultPrevented)return c;if("function"==typeof f){var i=f.call(this.el,d,e,this.m);"boolean"==typeof i&&(i={x:i,y:i}),i.x===!0?this.el.x(d):i.x!==!1&&this.el.x(i.x),i.y===!0?this.el.y(e):i.y!==!1&&this.el.y(i.y)}else"object"==typeof f&&(null!=f.minX&&df.maxX-b.width&&(d=f.maxX-b.width,g=d-this.startPoints.box.x),null!=f.minY&&ef.maxY-b.height&&(e=f.maxY-b.height,h=e-this.startPoints.box.y),null!=f.snapToGrid&&(d-=d%f.snapToGrid,e-=e%f.snapToGrid,g-=g%f.snapToGrid,h-=h%f.snapToGrid),this.el instanceof SVG.G?this.el.matrix(this.startPoints.transform).transform({x:g,y:h},!0):this.el.move(d,e));return c},a.prototype.end=function(a){var b=this.drag(a);this.el.fire("dragend",{event:a,p:b,m:this.m,handler:this}),SVG.off(window,"mousemove.drag"),SVG.off(window,"touchmove.drag"),SVG.off(window,"mouseup.drag"),SVG.off(window,"touchend.drag")},SVG.extend(SVG.Element,{draggable:function(b,c){("function"==typeof b||"object"==typeof b)&&(c=b,b=!0);var d=this.remember("_draggable")||new a(this);return b="undefined"==typeof b?!0:b,b?d.init(c||{},b):(this.off("mousedown.drag"),this.off("touchstart.drag")),this}})}).call(this); \ No newline at end of file diff --git a/resource/web/js/svg.js b/hal-core/resources/web/js/lib/svg.js old mode 100755 new mode 100644 similarity index 76% rename from resource/web/js/svg.js rename to hal-core/resources/web/js/lib/svg.js index 3bbdf83c..e1f97edc --- a/resource/web/js/svg.js +++ b/hal-core/resources/web/js/lib/svg.js @@ -1,14 +1,15 @@ /*! * svg.js - A lightweight library for manipulating and animating SVG. -* @version 2.3.2 -* http://www.svgjs.com +* @version 2.7.1 +* https://svgdotjs.github.io/ * -* @copyright Wout Fierens +* @copyright Wout Fierens * @license MIT * -* BUILT: Tue Jun 21 2016 10:02:37 GMT+0200 (Mitteleuropäische Sommerzeit) +* BUILT: Fri Nov 30 2018 10:01:55 GMT+0100 (GMT+01:00) */; (function(root, factory) { + /* istanbul ignore next */ if (typeof define === 'function' && define.amd) { define(function(){ return factory(root, root.document) @@ -20,8 +21,12 @@ } }(typeof window !== "undefined" ? window : this, function(window, document) { +// Find global reference - uses 'this' by default when available, +// falls back to 'window' otherwise (for bundlers like Webpack) +var globalRef = (typeof this !== "undefined") ? this : window; + // The main wrapping element -var SVG = this.SVG = function(element) { +var SVG = globalRef.SVG = function(element) { if (SVG.supported) { element = new SVG.Doc(element) @@ -123,7 +128,7 @@ SVG.adopt = function(node) { // adopt with element-specific settings if (node.nodeName == 'svg') - element = node.parentNode instanceof SVGElement ? new SVG.Nested : new SVG.Doc + element = node.parentNode instanceof window.SVGElement ? new SVG.Nested : new SVG.Doc else if (node.nodeName == 'linearGradient') element = new SVG.Gradient('linear') else if (node.nodeName == 'radialGradient') @@ -152,12 +157,12 @@ SVG.adopt = function(node) { SVG.prepare = function() { // Select document body and create invisible svg element var body = document.getElementsByTagName('body')[0] - , draw = (body ? new SVG.Doc(body) : new SVG.Doc(document.documentElement).nested()).size(2, 0) + , draw = (body ? new SVG.Doc(body) : SVG.adopt(document.documentElement).nested()).size(2, 0) // Create parser object SVG.parser = { body: body || document.documentElement - , draw: draw.style('opacity:0;position:fixed;left:100%;top:100%;overflow:hidden') + , draw: draw.style('opacity:0;position:absolute;left:-100%;top:-100%;overflow:hidden').attr('focusable', 'false').node , poly: draw.polyline().node , path: draw.path().node , native: SVG.create('svg') @@ -187,11 +192,8 @@ SVG.regex = { // Parse reference id , reference: /#([a-z0-9\-_]+)/i - // Parse matrix wrapper -, matrix: /matrix\(|\)/g - - // Elements of a matrix -, matrixElements: /,*\s+|,/ + // splits a transformation chain +, transforms: /\)\s*,?\s*/ // Whitespace , whitespace: /\s/g @@ -217,16 +219,13 @@ SVG.regex = { // Test for image url , isImage: /\.(jpg|jpeg|png|gif|svg)(\?[^=]+.*)?/i + // split at whitespace and comma +, delimiter: /[\s,]+/ + // The following regex are used to parse the d attribute of a path - // Replaces all negative exponents -, negExp: /e\-/gi - - // Replaces all comma -, comma: /,/g - - // Replaces all hyphens -, hyphen: /\-/g + // Matches all hyphens which are not after an exponent +, hyphen: /([^e])\-/gi // Replaces and tests for all path letters , pathLetters: /[MLHVCSQTAZ]/gi @@ -234,16 +233,16 @@ SVG.regex = { // yes we need this one, too , isPathLetter: /[MLHVCSQTAZ]/i - // split at whitespaces -, whitespaces: /\s+/ + // matches 0.154.23.45 +, numbersWithDots: /((\d?\.\d+(?:e[+-]?\d+)?)((?:\.\d+(?:e[+-]?\d+)?)+))+/gi - // matches X -, X: /X/g + // matches . +, dots: /\./g } SVG.utils = { - // Map function - map: function(array, block) { + // Map function + map: function(array, block) { var i , il = array.length , result = [] @@ -254,16 +253,31 @@ SVG.utils = { return result } + // Filter function +, filter: function(array, block) { + var i + , il = array.length + , result = [] + + for (i = 0; i < il; i++) + if (block(array[i])) + result.push(array[i]) + + return result + } + // Degrees to radians , radians: function(d) { return d % 360 * Math.PI / 180 } + // Radians to degrees , degrees: function(r) { return r * 180 / Math.PI % 360 } -, filterSVGElements: function(p) { - return [].filter.call(p, function(el){ return el instanceof SVGElement }) + +, filterSVGElements: function(nodes) { + return this.filter( nodes, function(el) { return el instanceof window.SVGElement }) } } @@ -318,7 +332,7 @@ SVG.Color = function(color) { if (typeof color === 'string') { if (SVG.regex.isRgb.test(color)) { // get rgb values - match = SVG.regex.rgb.exec(color.replace(/\s/g,'')) + match = SVG.regex.rgb.exec(color.replace(SVG.regex.whitespace,'')) // parse numeric values this.r = parseInt(match[1]) @@ -481,7 +495,7 @@ SVG.extend(SVG.Array, { } // Strip unnecessary whitespace , split: function(string) { - return string.trim().split(/\s+/) + return string.trim().split(SVG.regex.delimiter).map(parseFloat) } // Reverse array , reverse: function() { @@ -489,15 +503,20 @@ SVG.extend(SVG.Array, { return this } - +, clone: function() { + var clone = new this.constructor() + clone.value = array_clone(this.value) + return clone + } }) // Poly points array SVG.PointArray = function(array, fallback) { - this.constructor.call(this, array, fallback || [[0,0]]) + SVG.Array.call(this, array, fallback || [[0,0]]) } // Inherit from SVG.Array SVG.PointArray.prototype = new SVG.Array +SVG.PointArray.prototype.constructor = SVG.PointArray SVG.extend(SVG.PointArray, { // Convert array to string @@ -531,22 +550,35 @@ SVG.extend(SVG.PointArray, { return new SVG.PointArray(array) } - // Parse point string + // Parse point string and flat array , parse: function(array) { + var points = [] + array = array.valueOf() - // if already is an array, no need to parse it - if (Array.isArray(array)) return array - - // split points - array = this.split(array) - - // parse points - for (var i = 0, il = array.length, p, points = []; i < il; i++) { - p = array[i].split(',') - points.push([parseFloat(p[0]), parseFloat(p[1])]) + // if it is an array + if (Array.isArray(array)) { + // and it is not flat, there is no need to parse it + if(Array.isArray(array[0])) { + // make sure to use a clone + return array.map(function (el) { return el.slice() }) + } else if (array[0].x != null){ + // allow point objects to be passed + return array.map(function (el) { return [el.x, el.y] }) + } + } else { // Else, it is considered as a string + // parse points + array = array.trim().split(SVG.regex.delimiter).map(parseFloat) } + // validate points - https://svgwg.org/svg2-draft/shapes.html#DataTypePoints + // Odd number of coordinates is an error. In such cases, drop the last odd coordinate. + if (array.length % 2 !== 0) array.pop() + + // wrap points in two-tuples and parse points as floats + for(var i = 0, len = array.length; i < len; i = i + 2) + points.push([ array[i], array[i+1] ]) + return points } // Move point string @@ -570,8 +602,8 @@ SVG.extend(SVG.PointArray, { // recalculate position of all points according to new size for (i = this.value.length - 1; i >= 0; i--) { - this.value[i][0] = ((this.value[i][0] - box.x) * width) / box.width + box.x - this.value[i][1] = ((this.value[i][1] - box.y) * height) / box.height + box.y + if(box.width) this.value[i][0] = ((this.value[i][0] - box.x) * width) / box.width + box.x + if(box.height) this.value[i][1] = ((this.value[i][1] - box.y) * height) / box.height + box.y } return this @@ -582,15 +614,89 @@ SVG.extend(SVG.PointArray, { return SVG.parser.poly.getBBox() } - }) + +var pathHandlers = { + M: function(c, p, p0) { + p.x = p0.x = c[0] + p.y = p0.y = c[1] + + return ['M', p.x, p.y] + }, + L: function(c, p) { + p.x = c[0] + p.y = c[1] + return ['L', c[0], c[1]] + }, + H: function(c, p) { + p.x = c[0] + return ['H', c[0]] + }, + V: function(c, p) { + p.y = c[0] + return ['V', c[0]] + }, + C: function(c, p) { + p.x = c[4] + p.y = c[5] + return ['C', c[0], c[1], c[2], c[3], c[4], c[5]] + }, + S: function(c, p) { + p.x = c[2] + p.y = c[3] + return ['S', c[0], c[1], c[2], c[3]] + }, + Q: function(c, p) { + p.x = c[2] + p.y = c[3] + return ['Q', c[0], c[1], c[2], c[3]] + }, + T: function(c, p) { + p.x = c[0] + p.y = c[1] + return ['T', c[0], c[1]] + }, + Z: function(c, p, p0) { + p.x = p0.x + p.y = p0.y + return ['Z'] + }, + A: function(c, p) { + p.x = c[5] + p.y = c[6] + return ['A', c[0], c[1], c[2], c[3], c[4], c[5], c[6]] + } +} + +var mlhvqtcsa = 'mlhvqtcsaz'.split('') + +for(var i = 0, il = mlhvqtcsa.length; i < il; ++i){ + pathHandlers[mlhvqtcsa[i]] = (function(i){ + return function(c, p, p0) { + if(i == 'H') c[0] = c[0] + p.x + else if(i == 'V') c[0] = c[0] + p.y + else if(i == 'A'){ + c[5] = c[5] + p.x, + c[6] = c[6] + p.y + } + else + for(var j = 0, jl = c.length; j < jl; ++j) { + c[j] = c[j] + (j%2 ? p.y : p.x) + } + + return pathHandlers[i](c, p, p0) + } + })(mlhvqtcsa[i].toUpperCase()) +} + // Path points array SVG.PathArray = function(array, fallback) { - this.constructor.call(this, array, fallback || [['M', 0, 0]]) + SVG.Array.call(this, array, fallback || [['M', 0, 0]]) } // Inherit from SVG.Array SVG.PathArray.prototype = new SVG.Array +SVG.PathArray.prototype.constructor = SVG.PathArray SVG.extend(SVG.PathArray, { // Convert array to string @@ -686,6 +792,63 @@ SVG.extend(SVG.PathArray, { return this } + // Test if the passed path array use the same path data commands as this path array +, equalCommands: function(pathArray) { + var i, il, equalCommands + + pathArray = new SVG.PathArray(pathArray) + + equalCommands = this.value.length === pathArray.value.length + for(i = 0, il = this.value.length; equalCommands && i < il; i++) { + equalCommands = this.value[i][0] === pathArray.value[i][0] + } + + return equalCommands + } + // Make path array morphable +, morph: function(pathArray) { + pathArray = new SVG.PathArray(pathArray) + + if(this.equalCommands(pathArray)) { + this.destination = pathArray + } else { + this.destination = null + } + + return this + } + // Get morphed path array at given position +, at: function(pos) { + // make sure a destination is defined + if (!this.destination) return this + + var sourceArray = this.value + , destinationArray = this.destination.value + , array = [], pathArray = new SVG.PathArray() + , i, il, j, jl + + // Animate has specified in the SVG spec + // See: https://www.w3.org/TR/SVG11/paths.html#PathElement + for (i = 0, il = sourceArray.length; i < il; i++) { + array[i] = [sourceArray[i][0]] + for(j = 1, jl = sourceArray[i].length; j < jl; j++) { + array[i][j] = sourceArray[i][j] + (destinationArray[i][j] - sourceArray[i][j]) * pos + } + // For the two flags of the elliptical arc command, the SVG spec say: + // Flags and booleans are interpolated as fractions between zero and one, with any non-zero value considered to be a value of one/true + // Elliptical arc command as an array followed by corresponding indexes: + // ['A', rx, ry, x-axis-rotation, large-arc-flag, sweep-flag, x, y] + // 0 1 2 3 4 5 6 7 + if(array[i][0] === 'A') { + array[i][4] = +(array[i][4] != 0) + array[i][5] = +(array[i][5] != 0) + } + } + + // Directly modify the value of a path array, this is done this way for performance + pathArray.value = array + return pathArray + } // Absolutize and parse path to array , parse: function(array) { // if it's already a patharray, no need to parse it @@ -695,45 +858,35 @@ SVG.extend(SVG.PathArray, { var i, x0, y0, s, seg, arr , x = 0 , y = 0 - , paramCnt = { 'M':2, 'L':2, 'H':1, 'V':1, 'C':6, 'S':4, 'Q':4, 'T':2, 'A':7 } + , paramCnt = { 'M':2, 'L':2, 'H':1, 'V':1, 'C':6, 'S':4, 'Q':4, 'T':2, 'A':7, 'Z':0 } if(typeof array == 'string'){ array = array - .replace(SVG.regex.negExp, 'X') // replace all negative exponents with certain char + .replace(SVG.regex.numbersWithDots, pathRegReplace) // convert 45.123.123 to 45.123 .123 .replace(SVG.regex.pathLetters, ' $& ') // put some room between letters and numbers - .replace(SVG.regex.hyphen, ' -') // add space before hyphen - .replace(SVG.regex.comma, ' ') // unify all spaces - .replace(SVG.regex.X, 'e-') // add back the expoent + .replace(SVG.regex.hyphen, '$1 -') // add space before hyphen .trim() // trim - .split(SVG.regex.whitespaces) // split into array - - // at this place there could be parts like ['3.124.854.32'] because we could not determine the point as seperator till now - // we fix this elements in the next loop - for(i = array.length; --i;){ - if(array[i].indexOf('.') != array[i].lastIndexOf('.')){ - var split = array[i].split('.') // split at the point - var first = [split.shift(), split.shift()].join('.') // join the first number together - array.splice.apply(array, [i, 1].concat(first, split.map(function(el){ return '.'+el }))) // add first and all other entries back to array - } - } + .split(SVG.regex.delimiter) // split into array }else{ array = array.reduce(function(prev, curr){ - return [].concat.apply(prev, curr) + return [].concat.call(prev, curr) }, []) } // array now is an array containing all parts of a path e.g. ['M', '0', '0', 'L', '30', '30' ...] - var arr = [] + , p = new SVG.Point() + , p0 = new SVG.Point() + , index = 0 + , len = array.length do{ - // Test if we have a path letter - if(SVG.regex.isPathLetter.test(array[0])){ - s = array[0] - array.shift() + if(SVG.regex.isPathLetter.test(array[index])){ + s = array[index] + ++index // If last letter was a move command and we got no new, it defaults to [L]ine }else if(s == 'M'){ s = 'L' @@ -741,80 +894,13 @@ SVG.extend(SVG.PathArray, { s = 'l' } - // add path letter as first element - seg = [s.toUpperCase()] + arr.push(pathHandlers[s].call(null, + array.slice(index, (index = index + paramCnt[s.toUpperCase()])).map(parseFloat), + p, p0 + ) + ) - // push all necessary parameters to segment - for(i = 0; i < paramCnt[seg[0]]; ++i){ - seg.push(parseFloat(array.shift())) - } - - // upper case - if(s == seg[0]){ - - if(s == 'M' || s == 'L' || s == 'C' || s == 'Q' || s == 'S' || s == 'T'){ - x = seg[paramCnt[seg[0]]-1] - y = seg[paramCnt[seg[0]]] - }else if(s == 'V'){ - y = seg[1] - }else if(s == 'H'){ - x = seg[1] - }else if(s == 'A'){ - x = seg[6] - y = seg[7] - } - - // lower case - }else{ - - // convert relative to absolute values - if(s == 'm' || s == 'l' || s == 'c' || s == 's' || s == 'q' || s == 't'){ - - seg[1] += x - seg[2] += y - - if(seg[3] != null){ - seg[3] += x - seg[4] += y - } - - if(seg[5] != null){ - seg[5] += x - seg[6] += y - } - - // move pointer - x = seg[paramCnt[seg[0]]-1] - y = seg[paramCnt[seg[0]]] - - }else if(s == 'v'){ - seg[1] += y - y = seg[1] - }else if(s == 'h'){ - seg[1] += x - x = seg[1] - }else if(s == 'a'){ - seg[6] += x - seg[7] += y - x = seg[6] - y = seg[7] - } - - } - - if(seg[0] == 'M'){ - x0 = x - y0 = y - } - - if(seg[0] == 'Z'){ - x = x0 - y = y0 - } - - arr.push(seg) - - }while(array.length) + }while(len > index) return arr @@ -827,6 +913,7 @@ SVG.extend(SVG.PathArray, { } }) + // Module for unit convertions SVG.Number = SVG.invent({ // Initialize @@ -886,19 +973,23 @@ SVG.Number = SVG.invent({ } // Add number , plus: function(number) { - return new SVG.Number(this + new SVG.Number(number), this.unit) + number = new SVG.Number(number) + return new SVG.Number(this + number, this.unit || number.unit) } // Subtract number , minus: function(number) { - return this.plus(-new SVG.Number(number)) + number = new SVG.Number(number) + return new SVG.Number(this - number, this.unit || number.unit) } // Multiply number , times: function(number) { - return new SVG.Number(this * new SVG.Number(number), this.unit) + number = new SVG.Number(number) + return new SVG.Number(this * number, this.unit || number.unit) } // Divide number , divide: function(number) { - return new SVG.Number(this / new SVG.Number(number), this.unit) + number = new SVG.Number(number) + return new SVG.Number(this / number, this.unit || number.unit) } // Convert to different unit , to: function(unit) { @@ -913,6 +1004,10 @@ SVG.Number = SVG.invent({ , morph: function(number) { this.destination = new SVG.Number(number) + if(number.relative) { + this.destination.value += this.value + } + return this } // Get morphed number at given position @@ -930,11 +1025,14 @@ SVG.Number = SVG.invent({ } }) + SVG.Element = SVG.invent({ // Initialize node create: function(node) { // make stroke value accessible dynamically this._stroke = SVG.defaults.attrs.stroke + this._event = null + this._events = {} // initialize data object this.dom = {} @@ -943,6 +1041,7 @@ SVG.Element = SVG.invent({ if (this.node = node) { this.type = node.nodeName this.node.instance = this + this._events = node._events || {} // store current attribute value this._stroke = node.getAttribute('stroke') || this._stroke @@ -985,7 +1084,7 @@ SVG.Element = SVG.invent({ } // Set element size to given width and height , size: function(width, height) { - var p = proportionalSize(this.bbox(), width, height) + var p = proportionalSize(this, width, height) return this .width(new SVG.Number(p.width)) @@ -993,6 +1092,9 @@ SVG.Element = SVG.invent({ } // Clone element , clone: function(parent) { + // write dom data to the dom so the clone can pickup the data + this.writeDataToDom() + // clone element and assign new id var clone = assignNewId(this.node.cloneNode(true)) @@ -1056,7 +1158,7 @@ SVG.Element = SVG.invent({ , classes: function() { var attr = this.attr('class') - return attr == null ? [] : attr.trim().split(/\s+/) + return attr == null ? [] : attr.trim().split(SVG.regex.delimiter) } // Return true if class exists on the node, false otherwise , hasClass: function(name) { @@ -1103,8 +1205,9 @@ SVG.Element = SVG.invent({ if(!type) return parent // loop trough ancestors if type is given - while(parent && parent.node instanceof SVGElement){ + while(parent && parent.node instanceof window.SVGElement){ if(typeof type === 'string' ? parent.matches(type) : parent instanceof type) return parent + if(!parent.node.parentNode || parent.node.parentNode.nodeName == '#document' || parent.node.parentNode.nodeName == '#document-fragment') return null // #759, #720 parent = SVG.adopt(parent.node.parentNode) } } @@ -1141,7 +1244,7 @@ SVG.Element = SVG.invent({ // act as a setter if svg is given if (svg && this instanceof SVG.Parent) { // dump raw svg - well.innerHTML = '' + svg.replace(/\n/, '').replace(/<(\w+)([^<]+?)\/>/g, '<$1$2>') + '' + well.innerHTML = '' + svg.replace(/\n/, '').replace(/<([\w:-]+)([^<]+?)\/>/g, '<$1$2>') + '' // transplant nodes for (var i = 0, il = well.firstChild.childNodes.length; i < il; i++) @@ -1221,7 +1324,9 @@ SVG.Situation = SVG.invent({ this.finish = this.start + this.duration this.ease = o.ease - this.loop = false + // this.loop is incremented from 0 to this.loops + // it is also incremented when in an infinite loop (when this.loops is true) + this.loop = 0 this.loops = false this.animations = { @@ -1253,9 +1358,6 @@ SVG.Situation = SVG.invent({ }) -SVG.Delay = function(delay){ - this.delay = new SVG.Number(delay).valueOf() -} SVG.FX = SVG.invent({ @@ -1267,6 +1369,10 @@ SVG.FX = SVG.invent({ this.paused = false this.lastPos = 0 this.pos = 0 + // The absolute position of an animation is its position in the context of its complete duration (including delay and loops) + // When performing a delay, absPos is below 0 and when performing a loop, its value is above 1 + this.absPos = 0 + this._speed = 1 } , extend: { @@ -1303,14 +1409,20 @@ SVG.FX = SVG.invent({ * @return this.target() */ , delay: function(delay){ - var delay = new SVG.Delay(delay) + // The delay is performed by an empty situation with its duration + // attribute set to the duration of the delay + var situation = new SVG.Situation({ + duration: delay, + delay: 0, + ease: SVG.easing['-'] + }) - return this.queue(delay) + return this.queue(situation) } /** * sets or returns the target of this animation - * @param null || target SVG.Elemenet which should be set as new target + * @param null || target SVG.Element which should be set as new target * @return target || this */ , target: function(target){ @@ -1322,49 +1434,52 @@ SVG.FX = SVG.invent({ return this._target } - // returns the position at a given time - , timeToPos: function(timestamp){ - return (timestamp - this.situation.start) / (this.situation.duration) + // returns the absolute position at a given time + , timeToAbsPos: function(timestamp){ + return (timestamp - this.situation.start) / (this.situation.duration/this._speed) } - // returns the timestamp from a given positon - , posToTime: function(pos){ - return this.situation.duration * pos + this.situation.start + // returns the timestamp from a given absolute positon + , absPosToTime: function(absPos){ + return this.situation.duration/this._speed * absPos + this.situation.start } // starts the animationloop , startAnimFrame: function(){ this.stopAnimFrame() - this.animationFrame = requestAnimationFrame(function(){ this.step() }.bind(this)) + this.animationFrame = window.requestAnimationFrame(function(){ this.step() }.bind(this)) } // cancels the animationframe , stopAnimFrame: function(){ - cancelAnimationFrame(this.animationFrame) + window.cancelAnimationFrame(this.animationFrame) } - // kicks off the animation - only does something when the queue is curretly not active and at least one situation is set + // kicks off the animation - only does something when the queue is currently not active and at least one situation is set , start: function(){ // dont start if already started if(!this.active && this.situation){ - this.situation.start = +new Date + this.situation.delay - this.situation.finish = this.situation.start + this.situation.duration - - this.initAnimations() this.active = true - this.startAnimFrame() + this.startCurrent() } return this } + // start the current situation + , startCurrent: function(){ + this.situation.start = +new Date + this.situation.delay/this._speed + this.situation.finish = this.situation.start + this.situation.duration/this._speed + return this.initAnimations().step() + } + /** * adds a function / Situation to the animation queue * @param fn function / situation to add * @return this */ , queue: function(fn){ - if(typeof fn == 'function' || fn instanceof SVG.Situation || fn instanceof SVG.Delay) + if(typeof fn == 'function' || fn instanceof SVG.Situation) this.situations.push(fn) if(!this.situation) this.situation = this.situations.shift() @@ -1378,29 +1493,18 @@ SVG.FX = SVG.invent({ */ , dequeue: function(){ // stop current animation - this.situation && this.situation.stop && this.situation.stop() + this.stop() // get next animation from queue this.situation = this.situations.shift() if(this.situation){ - - var fn = function(){ - if(this.situation instanceof SVG.Situation) - this.initAnimations().at(0) - else if(this.situation instanceof SVG.Delay) - this.dequeue() - else - this.situation.call(this) - }.bind(this) - - // start next animation - if(this.situation.delay){ - setTimeout(function(){fn()}, this.situation.delay) - }else{ - fn() + if(this.situation instanceof SVG.Situation) { + this.start() + } else { + // If it is not a SVG.Situation, then it is a function, we execute it + this.situation.call(this) } - } return this @@ -1409,45 +1513,42 @@ SVG.FX = SVG.invent({ // updates all animations to the current state of the element // this is important when one property could be changed from another property , initAnimations: function() { - var i + var i, j, source var s = this.situation if(s.init) return this for(i in s.animations){ + source = this.target()[i]() - if(i == 'viewbox'){ - s.animations[i] = this.target().viewbox().morph(s.animations[i]) - }else{ - - // TODO: this is not a clean clone of the array. We may have some unchecked references - s.animations[i].value = (i == 'plot' ? this.target().array().value : this.target()[i]()) - - // sometimes we get back an object and not the real value, fix this - if(s.animations[i].value.value){ - s.animations[i].value = s.animations[i].value.value - } - - if(s.animations[i].relative) - s.animations[i].destination.value = s.animations[i].destination.value + s.animations[i].value - + if(!Array.isArray(source)) { + source = [source] } + if(!Array.isArray(s.animations[i])) { + s.animations[i] = [s.animations[i]] + } + + //if(s.animations[i].length > source.length) { + // source.concat = source.concat(s.animations[i].slice(source.length, s.animations[i].length)) + //} + + for(j = source.length; j--;) { + // The condition is because some methods return a normal number instead + // of a SVG.Number + if(s.animations[i][j] instanceof SVG.Number) + source[j] = new SVG.Number(source[j]) + + s.animations[i][j] = source[j].morph(s.animations[i][j]) + } } for(i in s.attrs){ - if(s.attrs[i] instanceof SVG.Color){ - var color = new SVG.Color(this.target().attr(i)) - s.attrs[i].r = color.r - s.attrs[i].g = color.g - s.attrs[i].b = color.b - }else{ - s.attrs[i].value = this.target().attr(i)// + s.attrs[i].value - } + s.attrs[i] = new SVG.MorphObj(this.target().attr(i), s.attrs[i]) } for(i in s.styles){ - s.styles[i].value = this.target().style(i) + s.styles[i] = new SVG.MorphObj(this.target().style(i), s.styles[i]) } s.initialTransformation = this.target().matrixify() @@ -1469,28 +1570,20 @@ SVG.FX = SVG.invent({ * @return this */ , stop: function(jumpToEnd, clearQueue){ - if(!this.active) this.start() + var active = this.active + this.active = false if(clearQueue){ this.clearQueue() } - this.active = false - if(jumpToEnd && this.situation){ - - this.situation.loop = false - - if(this.situation.loops % 2 == 0 && this.situation.reversing){ - this.situation.reversed = true - } - - this.at(1) - + // initialize the situation if it was not + !active && this.startCurrent() + this.atEnd() } this.stopAnimFrame() - clearTimeout(this.timeout) return this.clearCurrent() } @@ -1503,7 +1596,7 @@ SVG.FX = SVG.invent({ var temp = this.situation this.stop() this.situation = temp - this.at(0) + this.atStart() } return this } @@ -1520,27 +1613,69 @@ SVG.FX = SVG.invent({ return this } + // set the internal animation pointer at the start position, before any loops, and updates the visualisation + , atStart: function() { + return this.at(0, true) + } + + // set the internal animation pointer at the end position, after all the loops, and updates the visualisation + , atEnd: function() { + if (this.situation.loops === true) { + // If in a infinite loop, we end the current iteration + this.situation.loops = this.situation.loop + 1 + } + + if(typeof this.situation.loops == 'number') { + // If performing a finite number of loops, we go after all the loops + return this.at(this.situation.loops, true) + } else { + // If no loops, we just go at the end + return this.at(1, true) + } + } + // set the internal animation pointer to the specified position and updates the visualisation - , at: function(pos){ - this.pos = pos - this.situation.start = +new Date - pos * this.situation.duration - this.situation.finish = this.situation.start + this.situation.duration + // if isAbsPos is true, pos is treated as an absolute position + , at: function(pos, isAbsPos){ + var durDivSpd = this.situation.duration/this._speed + + this.absPos = pos + // If pos is not an absolute position, we convert it into one + if (!isAbsPos) { + if (this.situation.reversed) this.absPos = 1 - this.absPos + this.absPos += this.situation.loop + } + + this.situation.start = +new Date - this.absPos * durDivSpd + this.situation.finish = this.situation.start + durDivSpd + return this.step(true) } - // speeds up the animation by the given factor - // this changes the duration of the animation + /** + * sets or returns the speed of the animations + * @param speed null || Number The new speed of the animations + * @return Number || this + */ , speed: function(speed){ - this.situation.duration = this.situation.duration * this.pos + (1-this.pos) * this.situation.duration / speed - this.situation.finish = this.situation.start + this.situation.duration - return this.at(this.pos) + if (speed === 0) return this.pause() + + if (speed) { + this._speed = speed + // We use an absolute position here so that speed can affect the delay before the animation + return this.at(this.absPos, true) + } else return this._speed } + // Make loopable , loop: function(times, reverse) { - // store current loop and total loops - this.situation.loop = this.situation.loops = times || true + var c = this.last() - if(reverse) this.last().reversing = true + // store total loops + c.loops = (times != null) ? times : true + c.loop = 0 + + if(reverse) c.reversing = true return this } @@ -1548,7 +1683,7 @@ SVG.FX = SVG.invent({ , pause: function(){ this.paused = true this.stopAnimFrame() - clearTimeout(this.timeout) + return this } @@ -1556,7 +1691,8 @@ SVG.FX = SVG.invent({ , play: function(){ if(!this.paused) return this this.paused = false - return this.at(this.pos) + // We use an absolute position here so that the delay before the animation can be paused + return this.at(this.absPos, true) } /** @@ -1599,7 +1735,8 @@ SVG.FX = SVG.invent({ } this.target().on('finished.fx', wrapper) - return this + + return this._callStart() } // adds a callback which is called whenever one animation step is performed @@ -1614,9 +1751,11 @@ SVG.FX = SVG.invent({ // see above this.target().off('during.fx', wrapper).on('during.fx', wrapper) - return this.after(function(){ + this.after(function(){ this.off('during.fx', wrapper) }) + + return this._callStart() } // calls after ALL animations in the queue are finished @@ -1628,7 +1767,8 @@ SVG.FX = SVG.invent({ // see above this.target().off('allfinished.fx', wrapper).on('allfinished.fx', wrapper) - return this + + return this._callStart() } // calls on every animation step for all animations @@ -1639,9 +1779,11 @@ SVG.FX = SVG.invent({ this.target().off('during.fx', wrapper).on('during.fx', wrapper) - return this.afterAll(function(){ + this.afterAll(function(){ this.off('during.fx', wrapper) }) + + return this._callStart() } , last: function(){ @@ -1651,8 +1793,7 @@ SVG.FX = SVG.invent({ // adds one property to the animations , add: function(method, args, type){ this.last()[type || 'animations'][method] = args - setTimeout(function(){this.start()}.bind(this), 0) - return this + return this._callStart() } /** perform one step of the animation @@ -1661,22 +1802,45 @@ SVG.FX = SVG.invent({ */ , step: function(ignoreTime){ - // convert current time to position - if(!ignoreTime) this.pos = this.timeToPos(+new Date) + // convert current time to an absolute position + if(!ignoreTime) this.absPos = this.timeToAbsPos(+new Date) - if(this.pos >= 1 && (this.situation.loop === true || (typeof this.situation.loop == 'number' && --this.situation.loop))){ + // This part convert an absolute position to a position + if(this.situation.loops !== false) { + var absPos, absPosInt, lastLoop - if(this.situation.reversing){ - this.situation.reversed = !this.situation.reversed + // If the absolute position is below 0, we just treat it as if it was 0 + absPos = Math.max(this.absPos, 0) + absPosInt = Math.floor(absPos) + + if(this.situation.loops === true || absPosInt < this.situation.loops) { + this.pos = absPos - absPosInt + lastLoop = this.situation.loop + this.situation.loop = absPosInt + } else { + this.absPos = this.situation.loops + this.pos = 1 + // The -1 here is because we don't want to toggle reversed when all the loops have been completed + lastLoop = this.situation.loop - 1 + this.situation.loop = this.situation.loops } - return this.at(this.pos-1) + + if(this.situation.reversing) { + // Toggle reversed if an odd number of loops as occured since the last call of step + this.situation.reversed = this.situation.reversed != Boolean((this.situation.loop - lastLoop) % 2) + } + + } else { + // If there are no loop, the absolute position must not be above 1 + this.absPos = Math.min(this.absPos, 1) + this.pos = this.absPos } + // while the absolute position can be below 0, the position must not be below 0 + if(this.pos < 0) this.pos = 0 + if(this.situation.reversed) this.pos = 1 - this.pos - // correct position - if(this.pos > 1)this.pos = 1 - if(this.pos < 0)this.pos = 0 // apply easing var eased = this.situation.ease(this.pos) @@ -1712,8 +1876,12 @@ SVG.FX = SVG.invent({ if(!this.situations.length){ this.target().fire('allfinished') - this.target().off('.fx') // there shouldnt be any binding left, but to make sure... - this.active = false + + // Recheck the length since the user may call animate in the afterAll callback + if(!this.situations.length){ + this.target().off('.fx') // there shouldnt be any binding left, but to make sure... + this.active = false + } } // start next animation @@ -1733,13 +1901,13 @@ SVG.FX = SVG.invent({ // calculates the step for every property and calls block with it , eachAt: function(){ - var i, at, self = this, target = this.target(), s = this.situation + var i, len, at, self = this, target = this.target(), s = this.situation // apply animations which can be called trough a method for(i in s.animations){ at = [].concat(s.animations[i]).map(function(el){ - return el.at ? el.at(s.ease(self.pos), self.pos) : el + return typeof el !== 'string' && el.at ? el.at(s.ease(self.pos), self.pos) : el }) target[i].apply(target, at) @@ -1750,7 +1918,7 @@ SVG.FX = SVG.invent({ for(i in s.attrs){ at = [i].concat(s.attrs[i]).map(function(el){ - return el.at ? el.at(s.ease(self.pos), self.pos) : el + return typeof el !== 'string' && el.at ? el.at(s.ease(self.pos), self.pos) : el }) target.attr.apply(target, at) @@ -1761,7 +1929,7 @@ SVG.FX = SVG.invent({ for(i in s.styles){ at = [i].concat(s.styles[i]).map(function(el){ - return el.at ? el.at(s.ease(self.pos), self.pos) : el + return typeof el !== 'string' && el.at ? el.at(s.ease(self.pos), self.pos) : el }) target.style.apply(target, at) @@ -1771,9 +1939,9 @@ SVG.FX = SVG.invent({ // animate initialTransformation which has to be chained if(s.transforms.length){ - // get inital initialTransformation + // get initial initialTransformation at = s.initialTransformation - for(i in s.transforms){ + for(i = 0, len = s.transforms.length; i < len; i++){ // get next transformation in chain var a = s.transforms[i] @@ -1782,7 +1950,7 @@ SVG.FX = SVG.invent({ if(a instanceof SVG.Matrix){ if(a.relative){ - at = at.multiply(a.at(s.ease(this.pos))) + at = at.multiply(new SVG.Matrix().morph(a).at(s.ease(this.pos))) }else{ at = at.morph(a).at(s.ease(this.pos)) } @@ -1809,11 +1977,16 @@ SVG.FX = SVG.invent({ // adds an once-callback which is called at a specific position and never again , once: function(pos, fn, isEased){ + var c = this.last() + if(!isEased) pos = c.ease(pos) - if(!isEased)pos = this.situation.ease(pos) + c.once[pos] = fn - this.situation.once[pos] = fn + return this + } + , _callStart: function() { + setTimeout(function(){this.start()}.bind(this), 0) return this } @@ -1856,6 +2029,16 @@ SVG.FX = SVG.invent({ return this } + // Set/Get the speed of the animations + , speed: function(speed) { + if (this.fx) + if (speed == null) + return this.fx.speed() + else + this.fx.speed(speed) + + return this + } } }) @@ -1866,11 +2049,18 @@ SVG.MorphObj = SVG.invent({ create: function(from, to){ // prepare color for morphing if(SVG.Color.isColor(to)) return new SVG.Color(from).morph(to) + // check if we have a list of values + if(SVG.regex.delimiter.test(from)) { + // prepare path for morphing + if(SVG.regex.pathLetters.test(from)) return new SVG.PathArray(from).morph(to) + // prepare value list for morphing + else return new SVG.Array(from).morph(to) + } // prepare number for morphing if(SVG.regex.numberAndUnit.test(to)) return new SVG.Number(from).morph(to) // prepare for plain morphing - this.value = 0 + this.value = from this.destination = to } @@ -1895,8 +2085,7 @@ SVG.extend(SVG.FX, { this.attr(key, a[key]) } else { - // the MorphObj takes care about the right function used - this.add(a, new SVG.MorphObj(null, v), 'attrs') + this.add(a, v, 'attrs') } return this @@ -1908,7 +2097,7 @@ SVG.extend(SVG.FX, { this.style(key, s[key]) else - this.add(s, new SVG.MorphObj(null, v), 'styles') + this.add(s, v, 'styles') return this } @@ -1919,7 +2108,7 @@ SVG.extend(SVG.FX, { return this } - var num = new SVG.Number().morph(x) + var num = new SVG.Number(x) num.relative = relative return this.add('x', num) } @@ -1930,17 +2119,17 @@ SVG.extend(SVG.FX, { return this } - var num = new SVG.Number().morph(y) + var num = new SVG.Number(y) num.relative = relative return this.add('y', num) } // Animatable center x-axis , cx: function(x) { - return this.add('cx', new SVG.Number().morph(x)) + return this.add('cx', new SVG.Number(x)) } // Animatable center y-axis , cy: function(y) { - return this.add('cy', new SVG.Number().morph(y)) + return this.add('cy', new SVG.Number(y)) } // Add animatable move , move: function(x, y) { @@ -1972,21 +2161,34 @@ SVG.extend(SVG.FX, { height = box.height / box.width * width } - this.add('width' , new SVG.Number().morph(width)) - .add('height', new SVG.Number().morph(height)) + this.add('width' , new SVG.Number(width)) + .add('height', new SVG.Number(height)) } return this } + // Add animatable width +, width: function(width) { + return this.add('width', new SVG.Number(width)) + } + // Add animatable height +, height: function(height) { + return this.add('height', new SVG.Number(height)) + } // Add animatable plot -, plot: function(p) { - return this.add('plot', this.target().array().morph(p)) +, plot: function(a, b, c, d) { + // Lines can be plotted with 4 arguments + if(arguments.length == 4) { + return this.plot([a, b, c, d]) + } + + return this.add('plot', new (this.target().morphArray)(a)) } // Add leading method , leading: function(value) { return this.target().leading ? - this.add('leading', new SVG.Number().morph(value)) : + this.add('leading', new SVG.Number(value)) : this } // Add animatable viewbox @@ -2015,25 +2217,97 @@ SVG.extend(SVG.FX, { return this } }) + +SVG.Box = SVG.invent({ + create: function(x, y, width, height) { + if (typeof x == 'object' && !(x instanceof SVG.Element)) { + // chromes getBoundingClientRect has no x and y property + return SVG.Box.call(this, x.left != null ? x.left : x.x , x.top != null ? x.top : x.y, x.width, x.height) + } else if (arguments.length == 4) { + this.x = x + this.y = y + this.width = width + this.height = height + } + + // add center, right, bottom... + fullBox(this) + } +, extend: { + // Merge rect box with another, return a new instance + merge: function(box) { + var b = new this.constructor() + + // merge boxes + b.x = Math.min(this.x, box.x) + b.y = Math.min(this.y, box.y) + b.width = Math.max(this.x + this.width, box.x + box.width) - b.x + b.height = Math.max(this.y + this.height, box.y + box.height) - b.y + + return fullBox(b) + } + + , transform: function(m) { + var xMin = Infinity, xMax = -Infinity, yMin = Infinity, yMax = -Infinity, p, bbox + + var pts = [ + new SVG.Point(this.x, this.y), + new SVG.Point(this.x2, this.y), + new SVG.Point(this.x, this.y2), + new SVG.Point(this.x2, this.y2) + ] + + pts.forEach(function(p) { + p = p.transform(m) + xMin = Math.min(xMin,p.x) + xMax = Math.max(xMax,p.x) + yMin = Math.min(yMin,p.y) + yMax = Math.max(yMax,p.y) + }) + + bbox = new this.constructor() + bbox.x = xMin + bbox.width = xMax-xMin + bbox.y = yMin + bbox.height = yMax-yMin + + fullBox(bbox) + + return bbox + } + } +}) + SVG.BBox = SVG.invent({ // Initialize create: function(element) { + SVG.Box.apply(this, [].slice.call(arguments)) + // get values if element is given - if (element) { + if (element instanceof SVG.Element) { var box - // yes this is ugly, but Firefox can be a bitch when it comes to elements that are not yet rendered + // yes this is ugly, but Firefox can be a pain when it comes to elements that are not yet rendered try { - // the element is NOT in the dom, throw error - if(!document.documentElement.contains(element.node)) throw new Exception('Element not in the dom') + if (!document.documentElement.contains){ + // This is IE - it does not support contains() for top-level SVGs + var topParent = element.node + while (topParent.parentNode){ + topParent = topParent.parentNode + } + if (topParent != document) throw new Exception('Element not in the dom') + } else { + // the element is NOT in the dom, throw error + if(!document.documentElement.contains(element.node)) throw new Exception('Element not in the dom') + } // find native bbox box = element.node.getBBox() } catch(e) { if(element instanceof SVG.Shape){ - var clone = element.clone(SVG.parser.draw) - box = clone.bbox() + var clone = element.clone(SVG.parser.draw.instance).show() + box = clone.node.getBBox() clone.remove() }else{ box = { @@ -2045,19 +2319,14 @@ SVG.BBox = SVG.invent({ } } - // plain x and y - this.x = box.x - this.y = box.y - - // plain width and height - this.width = box.width - this.height = box.height + SVG.Box.call(this, box) } - // add center, right and bottom - fullBox(this) } + // Define ancestor +, inherit: SVG.Box + // Define Parent , parent: SVG.Element @@ -2071,118 +2340,52 @@ SVG.BBox = SVG.invent({ }) -SVG.TBox = SVG.invent({ - // Initialize - create: function(element) { - // get values if element is given - if (element) { - var t = element.ctm().extract() - , box = element.bbox() +SVG.BBox.prototype.constructor = SVG.BBox - // width and height including transformations - this.width = box.width * t.scaleX - this.height = box.height * t.scaleY - // x and y including transformations - this.x = box.x + t.x - this.y = box.y + t.y - } - - // add center, right and bottom - fullBox(this) +SVG.extend(SVG.Element, { + tbox: function(){ + console.warn('Use of TBox is deprecated and mapped to RBox. Use .rbox() instead.') + return this.rbox(this.doc()) } - - // Define Parent -, parent: SVG.Element - - // Constructor -, construct: { - // Get transformed bounding box - tbox: function() { - return new SVG.TBox(this) - } - } - }) - SVG.RBox = SVG.invent({ // Initialize create: function(element) { - if (element) { - var e = element.doc().parent() - , box = element.node.getBoundingClientRect() - , zoom = 1 + SVG.Box.apply(this, [].slice.call(arguments)) - // get screen offset - this.x = box.left - this.y = box.top - - // subtract parent offset - this.x -= e.offsetLeft - this.y -= e.offsetTop - - while (e = e.offsetParent) { - this.x -= e.offsetLeft - this.y -= e.offsetTop - } - - // calculate cumulative zoom from svg documents - e = element - while (e.parent && (e = e.parent())) { - if (e.viewbox) { - zoom *= e.viewbox().zoom - this.x -= e.x() || 0 - this.y -= e.y() || 0 - } - } - - // recalculate viewbox distortion - this.width = box.width /= zoom - this.height = box.height /= zoom + if (element instanceof SVG.Element) { + SVG.Box.call(this, element.node.getBoundingClientRect()) } - - // add center, right and bottom - fullBox(this) - - // offset by window scroll position, because getBoundingClientRect changes when window is scrolled - this.x += window.pageXOffset - this.y += window.pageYOffset } +, inherit: SVG.Box + // define Parent , parent: SVG.Element +, extend: { + addOffset: function() { + // offset by window scroll position, because getBoundingClientRect changes when window is scrolled + this.x += window.pageXOffset + this.y += window.pageYOffset + return this + } + } + // Constructor , construct: { // Get rect box - rbox: function() { - return new SVG.RBox(this) + rbox: function(el) { + if (el) return new SVG.RBox(this).transform(el.screenCTM().inverse()) + return new SVG.RBox(this).addOffset() } } }) -// Add universal merge method -;[SVG.BBox, SVG.TBox, SVG.RBox].forEach(function(c) { - - SVG.extend(c, { - // Merge rect box with another, return a new instance - merge: function(box) { - var b = new c() - - // merge boxes - b.x = Math.min(this.x, box.x) - b.y = Math.min(this.y, box.y) - b.width = Math.max(this.x + this.width, box.x + box.width) - b.x - b.height = Math.max(this.y + this.height, box.y + box.height) - b.y - - return fullBox(b) - } - - }) - -}) +SVG.RBox.prototype.constructor = SVG.RBox SVG.Matrix = SVG.invent({ // Initialize @@ -2193,15 +2396,17 @@ SVG.Matrix = SVG.invent({ source = source instanceof SVG.Element ? source.matrixify() : typeof source === 'string' ? - stringToMatrix(source) : + arrayToMatrix(source.split(SVG.regex.delimiter).map(parseFloat)) : arguments.length == 6 ? arrayToMatrix([].slice.call(arguments)) : + Array.isArray(source) ? + arrayToMatrix(source) : typeof source === 'object' ? source : base // merge source for (i = abcdef.length - 1; i >= 0; --i) - this[abcdef[i]] = source && typeof source[abcdef[i]] === 'number' ? + this[abcdef[i]] = source[abcdef[i]] != null ? source[abcdef[i]] : base[abcdef[i]] } @@ -2263,26 +2468,6 @@ SVG.Matrix = SVG.invent({ , f: this.f + (this.destination.f - this.f) * pos }) - // process parametric rotation if present - if (this.param && this.param.to) { - // calculate current parametric position - var param = { - rotation: this.param.from.rotation + (this.param.to.rotation - this.param.from.rotation) * pos - , cx: this.param.from.cx - , cy: this.param.from.cy - } - - // rotate matrix - matrix = matrix.rotate( - (this.param.to.rotation - this.param.from.rotation * 2) * pos - , param.cx - , param.cy - ) - - // store current parametric values - matrix.param = param - } - return matrix } // Multiplies by given matrix @@ -2299,12 +2484,13 @@ SVG.Matrix = SVG.invent({ } // Scale matrix , scale: function(x, y, cx, cy) { - // support universal scale - if (arguments.length == 1 || arguments.length == 3) + // support uniformal scale + if (arguments.length == 1) { y = x - if (arguments.length == 3) { + } else if (arguments.length == 3) { cy = cx cx = y + y = x } return this.around(cx, cy, new SVG.Matrix(x, 0, 0, y, 0, 0)) @@ -2318,19 +2504,36 @@ SVG.Matrix = SVG.invent({ } // Flip matrix on x or y, at a given offset , flip: function(a, o) { - return a == 'x' ? this.scale(-1, 1, o, 0) : this.scale(1, -1, 0, o) + return a == 'x' ? + this.scale(-1, 1, o, 0) : + a == 'y' ? + this.scale(1, -1, 0, o) : + this.scale(-1, -1, a, o != null ? o : a) } // Skew , skew: function(x, y, cx, cy) { - return this.around(cx, cy, this.native().skewX(x || 0).skewY(y || 0)) + // support uniformal skew + if (arguments.length == 1) { + y = x + } else if (arguments.length == 3) { + cy = cx + cx = y + y = x + } + + // convert degrees to radians + x = SVG.utils.radians(x) + y = SVG.utils.radians(y) + + return this.around(cx, cy, new SVG.Matrix(1, Math.tan(y), Math.tan(x), 1, 0, 0)) } // SkewX , skewX: function(x, cx, cy) { - return this.around(cx, cy, this.native().skewX(x || 0)) + return this.skew(x, 0, cx, cy) } // SkewY , skewY: function(y, cx, cy) { - return this.around(cx, cy, this.native().skewY(y || 0)) + return this.skew(0, y, cx, cy) } // Transform around a center point , around: function(cx, cy, matrix) { @@ -2352,7 +2555,11 @@ SVG.Matrix = SVG.invent({ } // Convert matrix to string , toString: function() { - return 'matrix(' + this.a + ',' + this.b + ',' + this.c + ',' + this.d + ',' + this.e + ',' + this.f + ')' + // Construct the matrix directly, avoid values that are too small + return 'matrix(' + float32String(this.a) + ',' + float32String(this.b) + + ',' + float32String(this.c) + ',' + float32String(this.d) + + ',' + float32String(this.e) + ',' + float32String(this.f) + + ')' } } @@ -2367,6 +2574,16 @@ SVG.Matrix = SVG.invent({ }, // Get current screen matrix screenCTM: function() { + /* https://bugzilla.mozilla.org/show_bug.cgi?id=1344537 + This is needed because FF does not return the transformation matrix + for the inner coordinate system when getScreenCTM() is called on nested svgs. + However all other Browsers do that */ + if(this instanceof SVG.Nested) { + var rect = this.rect(1,1) + var m = rect.node.getScreenCTM() + rect.remove() + return new SVG.Matrix(m) + } return new SVG.Matrix(this.node.getScreenCTM()) } @@ -2384,8 +2601,8 @@ SVG.Point = SVG.invent({ {x:x[0], y:x[1]} : typeof x === 'object' ? {x:x.x, y:x.y} : - y != null ? - {x:x, y:y} : base + x != null ? + {x:x, y:(y != null ? y : x)} : base // If y has no value, then x is used has its value // merge source this.x = source.x @@ -2399,9 +2616,9 @@ SVG.Point = SVG.invent({ return new SVG.Point(this) } // Morph one point into another - , morph: function(point) { + , morph: function(x, y) { // store new destination - this.destination = new SVG.Point(point) + this.destination = new SVG.Point(x, y) return this } @@ -2506,10 +2723,6 @@ SVG.extend(SVG.Element, { else if (Array.isArray(v)) v = new SVG.Array(v) - // store parametric transformation values locally - else if (v instanceof SVG.Matrix && v.param) - this.param = v.param - // if the passed attribute is leading... if (a == 'leading') { // ... call the leading method instead @@ -2535,7 +2748,7 @@ SVG.extend(SVG.Element, { transform: function(o, relative) { // get target in case of the fx module, otherwise reference this var target = this - , matrix + , matrix, bbox // act as a getter if (typeof o !== 'object') { @@ -2590,13 +2803,13 @@ SVG.extend(SVG.Element, { matrix = matrix.scale(o.scaleX, o.scaleY, o.cx, o.cy) // act on skew - } else if (o.skewX != null || o.skewY != null) { + } else if (o.skew != null || o.skewX != null || o.skewY != null) { // ensure centre point ensureCentre(o, target) // ensure skew values on both axes - o.skewX = o.skewX != null ? o.skewX : 0 - o.skewY = o.skewY != null ? o.skewY : 0 + o.skewX = o.skew != null ? o.skew : o.skewX != null ? o.skewX : 0 + o.skewY = o.skew != null ? o.skew : o.skewY != null ? o.skewY : 0 if (!relative) { // absolute; reset skew values @@ -2608,10 +2821,19 @@ SVG.extend(SVG.Element, { // act on flip } else if (o.flip) { - matrix = matrix.flip( - o.flip - , o.offset == null ? target.bbox()['c' + o.flip] : o.offset - ) + if(o.flip == 'x' || o.flip == 'y') { + o.offset = o.offset == null ? target.bbox()['c' + o.flip] : o.offset + } else { + if(o.offset == null) { + bbox = target.bbox() + o.flip = bbox.cx + o.offset = bbox.cy + } else { + o.flip = o.offset + } + } + + matrix = new SVG.Matrix().flip(o.flip, o.offset) // act on translate } else if (o.x != null || o.y != null) { @@ -2633,7 +2855,7 @@ SVG.extend(SVG.FX, { transform: function(o, relative) { // get target in case of the fx module, otherwise reference this var target = this.target() - , matrix + , matrix, bbox // act as a getter if (typeof o !== 'object') { @@ -2682,10 +2904,19 @@ SVG.extend(SVG.FX, { // act on flip } else if (o.flip) { - matrix = new SVG.Matrix().morph(new SVG.Matrix().flip( - o.flip - , o.offset == null ? target.bbox()['c' + o.flip] : o.offset - )) + if(o.flip == 'x' || o.flip == 'y') { + o.offset = o.offset == null ? target.bbox()['c' + o.flip] : o.offset + } else { + if(o.offset == null) { + bbox = target.bbox() + o.flip = bbox.cx + o.offset = bbox.cy + } else { + o.flip = o.offset + } + } + + matrix = new SVG.Matrix().flip(o.flip, o.offset) // act on translate } else if (o.x != null || o.y != null) { @@ -2698,9 +2929,7 @@ SVG.extend(SVG.FX, { this.last().transforms.push(matrix) - setTimeout(function(){this.start()}.bind(this), 0) - - return this + return this._callStart() } }) @@ -2714,12 +2943,12 @@ SVG.extend(SVG.Element, { var matrix = (this.attr('transform') || '') // split transformations - .split(/\)\s*/).slice(0,-1).map(function(str){ + .split(SVG.regex.transforms).slice(0,-1).map(function(str){ // generate key => value pairs var kv = str.trim().split('(') - return [kv[0], kv[1].split(SVG.regex.matrixElements).map(function(str){ return parseFloat(str) })] + return [kv[0], kv[1].split(SVG.regex.delimiter).map(function(str){ return parseFloat(str) })] }) - // calculate every transformation into one matrix + // merge every transformation into one matrix .reduce(function(matrix, transform){ if(transform[0] == 'matrix') return matrix.multiply(arrayToMatrix(transform[1])) @@ -2733,9 +2962,7 @@ SVG.extend(SVG.Element, { toParent: function(parent) { if(this == parent) return this var ctm = this.screenCTM() - var temp = parent.rect(1,1) - var pCtm = temp.screenCTM().inverse() - temp.remove() + var pCtm = parent.screenCTM().inverse() this.addTo(parent).untransform().transform(pCtm.multiply(ctm)) @@ -2753,19 +2980,17 @@ SVG.Transformation = SVG.invent({ create: function(source, inversed){ if(arguments.length > 1 && typeof inversed != 'boolean'){ - return this.create([].slice.call(arguments)) - } - - if(typeof source == 'object'){ - for(var i = 0, len = this.arguments.length; i < len; ++i){ - this[this.arguments[i]] = source[this.arguments[i]] - } + return this.constructor.call(this, [].slice.call(arguments)) } if(Array.isArray(source)){ for(var i = 0, len = this.arguments.length; i < len; ++i){ this[this.arguments[i]] = source[i] } + } else if(typeof source == 'object'){ + for(var i = 0, len = this.arguments.length; i < len; ++i){ + this[this.arguments[i]] = source[this.arguments[i]] + } } this.inversed = false @@ -2778,7 +3003,10 @@ SVG.Transformation = SVG.invent({ , extend: { - at: function(pos){ + arguments: [] + , method: '' + + , at: function(pos){ var params = [] @@ -2799,6 +3027,12 @@ SVG.Transformation = SVG.invent({ o[this.arguments[i]] = typeof this[this.arguments[i]] == 'undefined' ? 0 : o[this.arguments[i]] } + // The method SVG.Matrix.extract which was used before calling this + // method to obtain a value for the parameter o doesn't return a cx and + // a cy so we use the ones that were provided to this object at its creation + o.cx = this.cx + o.cy = this.cy + this._undo = new SVG[capitalize(this.method)](o, true).at(1) return this @@ -2814,8 +3048,7 @@ SVG.Translate = SVG.invent({ , inherit: SVG.Transformation , create: function(source, inversed){ - if(typeof source == 'object') this.constructor.call(this, source, inversed) - else this.constructor.call(this, [].slice.call(arguments)) + this.constructor.apply(this, [].slice.call(arguments)) } , extend: { @@ -2831,8 +3064,7 @@ SVG.Rotate = SVG.invent({ , inherit: SVG.Transformation , create: function(source, inversed){ - if(typeof source == 'object') this.constructor.call(this, source, inversed) - else this.constructor.call(this, [].slice.call(arguments)) + this.constructor.apply(this, [].slice.call(arguments)) } , extend: { @@ -2844,6 +3076,7 @@ SVG.Rotate = SVG.invent({ } , undo: function(o){ this._undo = o + return this } } @@ -2855,8 +3088,7 @@ SVG.Scale = SVG.invent({ , inherit: SVG.Transformation , create: function(source, inversed){ - if(typeof source == 'object') this.constructor.call(this, source, inversed) - else this.constructor.call(this, [].slice.call(arguments)) + this.constructor.apply(this, [].slice.call(arguments)) } , extend: { @@ -2872,8 +3104,7 @@ SVG.Skew = SVG.invent({ , inherit: SVG.Transformation , create: function(source, inversed){ - if(typeof source == 'object') this.constructor.call(this, source, inversed) - else this.constructor.call(this, [].slice.call(arguments)) + this.constructor.apply(this, [].slice.call(arguments)) } , extend: { @@ -2897,12 +3128,14 @@ SVG.extend(SVG.Element, { } else if (SVG.regex.isCss.test(s)) { // parse css string - s = s.split(';') + s = s.split(/\s*;\s*/) + // filter out suffix ; and stuff like ;; + .filter(function(e) { return !!e }) + .map(function(e){ return e.split(/\s*:\s*/) }) // apply every definition individually - for (var i = 0; i < s.length; i++) { - v = s[i].split(':') - this.style(v[0].replace(/\s+/g, ''), v[1]) + while (v = s.pop()) { + this.style(v[0], v[1]) } } else { // act as a getter if the first and only argument is not an object @@ -2935,13 +3168,10 @@ SVG.Parent = SVG.invent({ } // Add given element at a position , add: function(element, i) { - if (!this.has(element)) { - // define insertion index if none given - i = i == null ? this.children().length : i - - // add element references - this.node.insertBefore(element.node, SVG.utils.filterSVGElements(this.node.childNodes)[i] || null) - } + if (i == null) + this.node.appendChild(element.node) + else if (element.node != this.node.childNodes[i]) + this.node.insertBefore(element.node, this.node.childNodes[i]) return this } @@ -2956,19 +3186,19 @@ SVG.Parent = SVG.invent({ } // Gets index of given element , index: function(element) { - return this.children().indexOf(element) + return [].slice.call(this.node.childNodes).indexOf(element.node) } // Get a element at the given index , get: function(i) { - return this.children()[i] + return SVG.adopt(this.node.childNodes[i]) } - // Get first child, skipping the defs node + // Get first child , first: function() { - return this.children()[0] + return this.get(0) } // Get the last child , last: function() { - return this.children()[this.children().length - 1] + return this.get(this.node.childNodes.length - 1) } // Iterates over all children and invokes a given block , each: function(block, deep) { @@ -3013,7 +3243,7 @@ SVG.Parent = SVG.invent({ SVG.extend(SVG.Parent, { ungroup: function(parent, depth) { - if(depth === 0 || this instanceof SVG.Defs) return this + if(depth === 0 || this instanceof SVG.Defs || this.node == SVG.parser.draw) return this parent = parent || (this instanceof SVG.Doc ? this : this.parent(SVG.Parent)) depth = depth || Infinity @@ -3132,28 +3362,21 @@ SVG.ViewBox = SVG.invent({ toString: function() { return this.x + ' ' + this.y + ' ' + this.width + ' ' + this.height } - , morph: function(v){ - - var v = arguments.length == 1 ? - [v.x, v.y, v.width, v.height] : - [].slice.call(arguments) - - this.destination = new SVG.ViewBox(v) - + , morph: function(x, y, width, height){ + this.destination = new SVG.ViewBox(x, y, width, height) return this - } , at: function(pos) { - if(!this.destination) return this + if(!this.destination) return this - return new SVG.ViewBox([ - this.x + (this.destination.x - this.x) * pos - , this.y + (this.destination.y - this.y) * pos - , this.width + (this.destination.width - this.width) * pos - , this.height + (this.destination.height - this.height) * pos - ]) + return new SVG.ViewBox([ + this.x + (this.destination.x - this.x) * pos + , this.y + (this.destination.y - this.y) * pos + , this.width + (this.destination.width - this.width) * pos + , this.height + (this.destination.height - this.height) * pos + ]) } @@ -3166,166 +3389,160 @@ SVG.ViewBox = SVG.invent({ , construct: { // get/set viewbox - viewbox: function(v) { + viewbox: function(x, y, width, height) { if (arguments.length == 0) // act as a getter if there are no arguments return new SVG.ViewBox(this) // otherwise act as a setter - v = arguments.length == 1 ? - [v.x, v.y, v.width, v.height] : - [].slice.call(arguments) - - return this.attr('viewBox', v) + return this.attr('viewBox', new SVG.ViewBox(x, y, width, height)) } } }) // Add events to elements -;[ 'click' - , 'dblclick' - , 'mousedown' - , 'mouseup' - , 'mouseover' - , 'mouseout' - , 'mousemove' - // , 'mouseenter' -> not supported by IE - // , 'mouseleave' -> not supported by IE - , 'touchstart' - , 'touchmove' - , 'touchleave' - , 'touchend' - , 'touchcancel' ].forEach(function(event) { - // add event to SVG.Element - SVG.Element.prototype[event] = function(f) { - var self = this +;[ 'click', + 'dblclick', + 'mousedown', + 'mouseup', + 'mouseover', + 'mouseout', + 'mousemove', + 'mouseenter', + 'mouseleave', + 'touchstart', + 'touchmove', + 'touchleave', + 'touchend', + 'touchcancel' ].forEach(function (event) { + // add event to SVG.Element + SVG.Element.prototype[event] = function (f) { + // bind event to element rather than element node + if (f == null) { + SVG.off(this, event) + } else { + SVG.on(this, event, f) + } + return this + } + }) - // bind event to element rather than element node - this.node['on' + event] = typeof f == 'function' ? - function() { return f.apply(self, arguments) } : null - - return this - } - -}) - -// Initialize listeners stack -SVG.listeners = [] -SVG.handlerMap = [] SVG.listenerId = 0 // Add event binder in the SVG namespace -SVG.on = function(node, event, listener, binding) { - // create listener, get object-index - var l = listener.bind(binding || node.instance || node) - , index = (SVG.handlerMap.indexOf(node) + 1 || SVG.handlerMap.push(node)) - 1 - , ev = event.split('.')[0] - , ns = event.split('.')[1] || '*' +SVG.on = function (node, events, listener, binding, options) { + var l = listener.bind(binding || node) + var n = node instanceof SVG.Element ? node.node : node + // ensure instance object for nodes which are not adopted + n.instance = n.instance || {_events: {}} - // ensure valid object - SVG.listeners[index] = SVG.listeners[index] || {} - SVG.listeners[index][ev] = SVG.listeners[index][ev] || {} - SVG.listeners[index][ev][ns] = SVG.listeners[index][ev][ns] || {} + var bag = n.instance._events - if(!listener._svgjsListenerId) - listener._svgjsListenerId = ++SVG.listenerId + // add id to listener + if (!listener._svgjsListenerId) { listener._svgjsListenerId = ++SVG.listenerId } - // reference listener - SVG.listeners[index][ev][ns][listener._svgjsListenerId] = l + events.split(SVG.regex.delimiter).forEach(function (event) { + var ev = event.split('.')[0] + var ns = event.split('.')[1] || '*' - // add listener - node.addEventListener(ev, l, false) + // ensure valid object + bag[ev] = bag[ev] || {} + bag[ev][ns] = bag[ev][ns] || {} + + // reference listener + bag[ev][ns][listener._svgjsListenerId] = l + + // add listener + n.addEventListener(ev, l, options || false) + }) } // Add event unbinder in the SVG namespace -SVG.off = function(node, event, listener) { - var index = SVG.handlerMap.indexOf(node) - , ev = event && event.split('.')[0] - , ns = event && event.split('.')[1] - - if(index == -1) return - - if (listener) { - if(typeof listener == 'function') listener = listener._svgjsListenerId - if(!listener) return - - // remove listener reference - if (SVG.listeners[index][ev] && SVG.listeners[index][ev][ns || '*']) { - // remove listener - node.removeEventListener(ev, SVG.listeners[index][ev][ns || '*'][listener], false) - - delete SVG.listeners[index][ev][ns || '*'][listener] - } - - } else if (ns && ev) { - // remove all listeners for a namespaced event - if (SVG.listeners[index][ev] && SVG.listeners[index][ev][ns]) { - for (listener in SVG.listeners[index][ev][ns]) - SVG.off(node, [ev, ns].join('.'), listener) - - delete SVG.listeners[index][ev][ns] - } - - } else if (ns){ - // remove all listeners for a specific namespace - for(event in SVG.listeners[index]){ - for(namespace in SVG.listeners[index][event]){ - if(ns === namespace){ - SVG.off(node, [event, ns].join('.')) - } - } - } - - } else if (ev) { - // remove all listeners for the event - if (SVG.listeners[index][ev]) { - for (namespace in SVG.listeners[index][ev]) - SVG.off(node, [ev, namespace].join('.')) - - delete SVG.listeners[index][ev] - } - - } else { - // remove all listeners on a given node - for (event in SVG.listeners[index]) - SVG.off(node, event) - - delete SVG.listeners[index] +SVG.off = function (node, events, listener, options) { + var n = node instanceof SVG.Element ? node.node : node + if (!n.instance) return + // listener can be a function or a number + if (typeof listener === 'function') { + listener = listener._svgjsListenerId + if (!listener) return } + + var bag = n.instance._events + + ;(events || '').split(SVG.regex.delimiter).forEach(function (event) { + var ev = event && event.split('.')[0] + var ns = event && event.split('.')[1] + var namespace, l + + if (listener) { + // remove listener reference + if (bag[ev] && bag[ev][ns || '*']) { + // removeListener + n.removeEventListener(ev, bag[ev][ns || '*'][listener], options || false) + + delete bag[ev][ns || '*'][listener] + } + } else if (ev && ns) { + // remove all listeners for a namespaced event + if (bag[ev] && bag[ev][ns]) { + for (l in bag[ev][ns]) { SVG.off(n, [ev, ns].join('.'), l) } + + delete bag[ev][ns] + } + } else if (ns) { + // remove all listeners for a specific namespace + for (event in bag) { + for (namespace in bag[event]) { + if (ns === namespace) { SVG.off(n, [event, ns].join('.')) } + } + } + } else if (ev) { + // remove all listeners for the event + if (bag[ev]) { + for (namespace in bag[ev]) { SVG.off(n, [ev, namespace].join('.')) } + + delete bag[ev] + } + } else { + // remove all listeners on a given node + for (event in bag) { SVG.off(n, event) } + + n.instance._events = {} + } + }) } -// SVG.extend(SVG.Element, { // Bind given event to listener - on: function(event, listener, binding) { - SVG.on(this.node, event, listener, binding) - + on: function (event, listener, binding, options) { + SVG.on(this, event, listener, binding, options) return this - } + }, // Unbind event from listener -, off: function(event, listener) { + off: function (event, listener) { SVG.off(this.node, event, listener) - return this - } - // Fire given event -, fire: function(event, data) { - + }, + fire: function (event, data) { // Dispatch event - if(event instanceof Event){ - this.node.dispatchEvent(event) - }else{ - this.node.dispatchEvent(new CustomEvent(event, {detail:data})) + if (event instanceof window.Event) { + this.node.dispatchEvent(event) + } else { + this.node.dispatchEvent(event = new SVG.CustomEvent(event, {detail: data, cancelable: true})) } - + this._event = event return this + }, + event: function() { + return this._event } }) + SVG.Defs = SVG.invent({ // Initialize node create: 'defs' @@ -3385,6 +3602,122 @@ SVG.G = SVG.invent({ } }) +SVG.Doc = SVG.invent({ + // Initialize node + create: function(element) { + if (element) { + // ensure the presence of a dom element + element = typeof element == 'string' ? + document.getElementById(element) : + element + + // If the target is an svg element, use that element as the main wrapper. + // This allows svg.js to work with svg documents as well. + if (element.nodeName == 'svg') { + this.constructor.call(this, element) + } else { + this.constructor.call(this, SVG.create('svg')) + element.appendChild(this.node) + this.size('100%', '100%') + } + + // set svg element attributes and ensure defs node + this.namespace().defs() + } + } + + // Inherit from +, inherit: SVG.Container + + // Add class methods +, extend: { + // Add namespaces + namespace: function() { + return this + .attr({ xmlns: SVG.ns, version: '1.1' }) + .attr('xmlns:xlink', SVG.xlink, SVG.xmlns) + .attr('xmlns:svgjs', SVG.svgjs, SVG.xmlns) + } + // Creates and returns defs element + , defs: function() { + if (!this._defs) { + var defs + + // Find or create a defs element in this instance + if (defs = this.node.getElementsByTagName('defs')[0]) + this._defs = SVG.adopt(defs) + else + this._defs = new SVG.Defs + + // Make sure the defs node is at the end of the stack + this.node.appendChild(this._defs.node) + } + + return this._defs + } + // custom parent method + , parent: function() { + if(!this.node.parentNode || this.node.parentNode.nodeName == '#document' || this.node.parentNode.nodeName == '#document-fragment') return null + return this.node.parentNode + } + // Fix for possible sub-pixel offset. See: + // https://bugzilla.mozilla.org/show_bug.cgi?id=608812 + , spof: function() { + var pos = this.node.getScreenCTM() + + if (pos) + this + .style('left', (-pos.e % 1) + 'px') + .style('top', (-pos.f % 1) + 'px') + + return this + } + + // Removes the doc from the DOM + , remove: function() { + if(this.parent()) { + this.parent().removeChild(this.node) + } + + return this + } + , clear: function() { + // remove children + while(this.node.hasChildNodes()) + this.node.removeChild(this.node.lastChild) + + // remove defs reference + delete this._defs + + // add back parser + if(!SVG.parser.draw.parentNode) + this.node.appendChild(SVG.parser.draw) + + return this + } + , clone: function (parent) { + // write dom data to the dom so the clone can pickup the data + this.writeDataToDom() + + // get reference to node + var node = this.node + + // clone element and assign new id + var clone = assignNewId(node.cloneNode(true)) + + // insert the clone in the given parent or after myself + if(parent) { + (parent.node || parent).appendChild(clone.node) + } else { + node.parentNode.insertBefore(clone.node, node.nextSibling) + } + + return clone + } + } + +}) + // ### This module adds backward / forward functionality to elements. // @@ -3493,7 +3826,7 @@ SVG.Mask = SVG.invent({ this.targets = [] // remove mask from parent - this.parent().removeElement(this) + SVG.Element.prototype.remove.call(this) return this } @@ -3753,88 +4086,6 @@ SVG.extend(SVG.Defs, { } }) -SVG.Doc = SVG.invent({ - // Initialize node - create: function(element) { - if (element) { - // ensure the presence of a dom element - element = typeof element == 'string' ? - document.getElementById(element) : - element - - // If the target is an svg element, use that element as the main wrapper. - // This allows svg.js to work with svg documents as well. - if (element.nodeName == 'svg') { - this.constructor.call(this, element) - } else { - this.constructor.call(this, SVG.create('svg')) - element.appendChild(this.node) - this.size('100%', '100%') - } - - // set svg element attributes and ensure defs node - this.namespace().defs() - } - } - - // Inherit from -, inherit: SVG.Container - - // Add class methods -, extend: { - // Add namespaces - namespace: function() { - return this - .attr({ xmlns: SVG.ns, version: '1.1' }) - .attr('xmlns:xlink', SVG.xlink, SVG.xmlns) - .attr('xmlns:svgjs', SVG.svgjs, SVG.xmlns) - } - // Creates and returns defs element - , defs: function() { - if (!this._defs) { - var defs - - // Find or create a defs element in this instance - if (defs = this.node.getElementsByTagName('defs')[0]) - this._defs = SVG.adopt(defs) - else - this._defs = new SVG.Defs - - // Make sure the defs node is at the end of the stack - this.node.appendChild(this._defs.node) - } - - return this._defs - } - // custom parent method - , parent: function() { - return this.node.parentNode.nodeName == '#document' ? null : this.node.parentNode - } - // Fix for possible sub-pixel offset. See: - // https://bugzilla.mozilla.org/show_bug.cgi?id=608812 - , spof: function(spof) { - var pos = this.node.getScreenCTM() - - if (pos) - this - .style('left', (-pos.e % 1) + 'px') - .style('top', (-pos.f % 1) + 'px') - - return this - } - - // Removes the doc from the DOM - , remove: function() { - if(this.parent()) { - this.parent().removeChild(this.node); - } - - return this; - } - } - -}) - SVG.Shape = SVG.invent({ // Initialize node create: function(element) { @@ -3884,12 +4135,23 @@ SVG.extend(SVG.Parent, { element: function(element, inherit) { return this.put(new SVG.Bare(element, inherit)) } - // Add symbol element -, symbol: function() { - return this.defs().element('symbol', SVG.Container) - } - }) + +SVG.Symbol = SVG.invent({ + // Initialize node + create: 'symbol' + + // Inherit from +, inherit: SVG.Container + +, construct: { + // create symbol + symbol: function() { + return this.put(new SVG.Symbol) + } + } +}) + SVG.Use = SVG.invent({ // Initialize node create: 'use' @@ -4011,7 +4273,7 @@ SVG.extend(SVG.Circle, SVG.Ellipse, { } // Custom size function , size: function(width, height) { - var p = proportionalSize(this.bbox(), width, height) + var p = proportionalSize(this, width, height) return this .rx(new SVG.Number(p.width).divide(2)) @@ -4036,7 +4298,9 @@ SVG.Line = SVG.invent({ } // Overwrite native plot() method , plot: function(x1, y1, x2, y2) { - if (typeof y1 !== 'undefined') + if (x1 == null) + return this.array() + else if (typeof y1 !== 'undefined') x1 = { x1: x1, y1: y1, x2: x2, y2: y2 } else x1 = new SVG.PointArray(x1).toLine() @@ -4049,7 +4313,7 @@ SVG.Line = SVG.invent({ } // Set element size to given width and height , size: function(width, height) { - var p = proportionalSize(this.bbox(), width, height) + var p = proportionalSize(this, width, height) return this.attr(this.array().size(p.width, p.height).toLine()) } @@ -4059,7 +4323,12 @@ SVG.Line = SVG.invent({ , construct: { // Create a line element line: function(x1, y1, x2, y2) { - return this.put(new SVG.Line).plot(x1, y1, x2, y2) + // make sure plot is called as a setter + // x1 is not necessarily a number, it can also be an array, a string and a SVG.PointArray + return SVG.Line.prototype.plot.apply( + this.put(new SVG.Line) + , x1 != null ? [x1, y1, x2, y2] : [0, 0, 0, 0] + ) } } }) @@ -4075,7 +4344,8 @@ SVG.Polyline = SVG.invent({ , construct: { // Create a wrapped polyline element polyline: function(p) { - return this.put(new SVG.Polyline).plot(p) + // make sure plot is called as a setter + return this.put(new SVG.Polyline).plot(p || new SVG.PointArray) } } }) @@ -4091,7 +4361,8 @@ SVG.Polygon = SVG.invent({ , construct: { // Create a wrapped polygon element polygon: function(p) { - return this.put(new SVG.Polygon).plot(p) + // make sure plot is called as a setter + return this.put(new SVG.Polygon).plot(p || new SVG.PointArray) } } }) @@ -4104,7 +4375,14 @@ SVG.extend(SVG.Polyline, SVG.Polygon, { } // Plot new path , plot: function(p) { - return this.attr('points', (this._array = new SVG.PointArray(p))) + return (p == null) ? + this.array() : + this.clear().attr('points', typeof p == 'string' ? p : (this._array = new SVG.PointArray(p))) + } + // Clear array cache +, clear: function() { + delete this._array + return this } // Move by left top corner , move: function(x, y) { @@ -4112,12 +4390,13 @@ SVG.extend(SVG.Polyline, SVG.Polygon, { } // Set element size to given width and height , size: function(width, height) { - var p = proportionalSize(this.bbox(), width, height) + var p = proportionalSize(this, width, height) return this.attr('points', this.array().size(p.width, p.height)) } }) + // unify all point to point elements SVG.extend(SVG.Line, SVG.Polyline, SVG.Polygon, { // Define morphable array @@ -4158,9 +4437,16 @@ SVG.Path = SVG.invent({ , array: function() { return this._array || (this._array = new SVG.PathArray(this.attr('d'))) } - // Plot new poly points - , plot: function(p) { - return this.attr('d', (this._array = new SVG.PathArray(p))) + // Plot new path + , plot: function(d) { + return (d == null) ? + this.array() : + this.clear().attr('d', typeof d == 'string' ? d : (this._array = new SVG.PathArray(d))) + } + // Clear array cache + , clear: function() { + delete this._array + return this } // Move by left top corner , move: function(x, y) { @@ -4176,7 +4462,7 @@ SVG.Path = SVG.invent({ } // Set element size to given width and height , size: function(width, height) { - var p = proportionalSize(this.bbox(), width, height) + var p = proportionalSize(this, width, height) return this.attr('d', this.array().size(p.width, p.height)) } @@ -4195,10 +4481,12 @@ SVG.Path = SVG.invent({ , construct: { // Create a wrapped path element path: function(d) { - return this.put(new SVG.Path).plot(d) + // make sure plot is called as a setter + return this.put(new SVG.Path).plot(d || new SVG.PathArray) } } }) + SVG.Image = SVG.invent({ // Initialize node create: 'image' @@ -4213,10 +4501,12 @@ SVG.Image = SVG.invent({ if (!url) return this var self = this - , img = document.createElement('img') + , img = new window.Image() // preload image - img.onload = function() { + SVG.on(img, 'load', function() { + SVG.off(img) + var p = self.parent(SVG.Pattern) if(p === null) return @@ -4237,7 +4527,15 @@ SVG.Image = SVG.invent({ , ratio: img.width / img.height , url: url }) - } + }) + + SVG.on(img, 'error', function(e){ + SVG.off(img) + + if (typeof self._error === 'function'){ + self._error.call(self, e) + } + }) return this.attr('href', (img.src = this.src = url), SVG.xlink) } @@ -4246,6 +4544,11 @@ SVG.Image = SVG.invent({ this._loaded = loaded return this } + + , error: function(error) { + this._error = error + return this + } } // Add parent method @@ -4275,25 +4578,12 @@ SVG.Text = SVG.invent({ // Add class methods , extend: { - clone: function(){ - // clone element and assign new id - var clone = assignNewId(this.node.cloneNode(true)) - - // insert the clone after myself - this.after(clone) - - return clone - } // Move over x-axis - , x: function(x) { + x: function(x) { // act as getter if (x == null) return this.attr('x') - // move lines as well if no textPath is present - if (!this.textPath) - this.lines().each(function() { if (this.dom.newLined) this.x(x) }) - return this.attr('x', x) } // Move over y-axis @@ -4305,7 +4595,7 @@ SVG.Text = SVG.invent({ if (y == null) return typeof oy === 'number' ? oy - o : oy - return this.attr('y', typeof y === 'number' ? y + o : y) + return this.attr('y', typeof y.valueOf() === 'number' ? y + o : y) } // Move center over x-axis , cx: function(x) { @@ -4395,9 +4685,8 @@ SVG.Text = SVG.invent({ this.lines().each(function() { if (this.dom.newLined) { - if (!this.textPath) + if (!self.textPath()) this.attr('x', self.attr('x')) - if(this.text() == '\n') { blankLineOffset += dy }else{ @@ -4533,8 +4822,9 @@ SVG.TextPath = SVG.invent({ // Add parent method , construct: { + morphArray: SVG.PathArray // Create path for text to run on - path: function(d) { + , path: function(d) { // create textPath element var path = new SVG.TextPath , track = this.doc().defs().path(d) @@ -4551,14 +4841,22 @@ SVG.TextPath = SVG.invent({ return this } + // return the array of the path track element + , array: function() { + var track = this.track() + + return track ? track.array() : null + } // Plot path if any , plot: function(d) { var track = this.track() + , pathArray = null - if (track) - track.plot(d) + if (track) { + pathArray = track.plot(d) + } - return this + return (d == null) ? pathArray : this } // Get the path track element , track: function() { @@ -4574,6 +4872,7 @@ SVG.TextPath = SVG.invent({ } } }) + SVG.Nested = SVG.invent({ // Initialize node create: function() { @@ -4733,6 +5032,8 @@ var sugar = { var i, extension = {} extension[m] = function(o) { + if (typeof o == 'undefined') + return this if (typeof o == 'string' || SVG.Color.isRgb(o) || (o && typeof o.fill === 'function')) this.attr(m, o) @@ -4756,7 +5057,9 @@ SVG.extend(SVG.Element, SVG.FX, { } // Map skew to transform , skew: function(x, y, cx, cy) { - return this.transform({ skewX: x, skewY: y, cx: cx, cy: cy }) + return arguments.length == 1 || arguments.length == 3 ? + this.transform({ skew: x, cx: y, cy: cx }) : + this.transform({ skewX: x, skewY: y, cx: cx, cy: cy }) } // Map scale to transform , scale: function(x, y, cx, cy) { @@ -4770,11 +5073,12 @@ SVG.extend(SVG.Element, SVG.FX, { } // Map flip to transform , flip: function(a, o) { - return this.transform({ flip: a, offset: o }) + o = typeof a == 'number' ? a : o + return this.transform({ flip: a || 'both', offset: o }) } // Map matrix to transform , matrix: function(m) { - return this.attr('transform', new SVG.Matrix(m)) + return this.attr('transform', new SVG.Matrix(arguments.length == 6 ? [].slice.call(arguments) : m)) } // Opacity , opacity: function(value) { @@ -4782,11 +5086,11 @@ SVG.extend(SVG.Element, SVG.FX, { } // Relative move over x axis , dx: function(x) { - return this.x((this instanceof SVG.FX ? 0 : this.x()) + x, true) + return this.x(new SVG.Number(x).plus(this instanceof SVG.FX ? 0 : this.x()), true) } // Relative move over y axis , dy: function(y) { - return this.y((this instanceof SVG.FX ? 0 : this.y()) + y, true) + return this.y(new SVG.Number(y).plus(this instanceof SVG.FX ? 0 : this.y()), true) } // Relative move over x and y axes , dmove: function(x, y) { @@ -4815,28 +5119,31 @@ SVG.extend(SVG.Path, { } }) -SVG.extend(SVG.Parent, SVG.Text, SVG.FX, { +SVG.extend(SVG.Parent, SVG.Text, SVG.Tspan, SVG.FX, { // Set font - font: function(o) { - for (var k in o) - k == 'leading' ? - this.leading(o[k]) : - k == 'anchor' ? - this.attr('text-anchor', o[k]) : - k == 'size' || k == 'family' || k == 'weight' || k == 'stretch' || k == 'variant' || k == 'style' ? - this.attr('font-'+ k, o[k]) : - this.attr(k, o[k]) + font: function(a, v) { + if (typeof a == 'object') { + for (v in a) this.font(v, a[v]) + } - return this + return a == 'leading' ? + this.leading(v) : + a == 'anchor' ? + this.attr('text-anchor', v) : + a == 'size' || a == 'family' || a == 'weight' || a == 'stretch' || a == 'variant' || a == 'style' ? + this.attr('font-'+ a, v) : + this.attr(a, v) } }) - SVG.Set = SVG.invent({ // Initialize create: function(members) { - // Set initial state - Array.isArray(members) ? this.members = members : this.clear() + if (members instanceof SVG.Set) { + this.members = members.members.slice() + } else { + Array.isArray(members) ? this.members = members : this.clear() + } } // Add class methods @@ -4904,25 +5211,19 @@ SVG.Set = SVG.invent({ } // Get the bounding box of all members included or empty box if set has no items , bbox: function(){ - var box = new SVG.BBox() - // return an empty box of there are no members if (this.members.length == 0) - return box + return new SVG.RBox() // get the first rbox and update the target bbox - var rbox = this.members[0].rbox() - box.x = rbox.x - box.y = rbox.y - box.width = rbox.width - box.height = rbox.height + var rbox = this.members[0].rbox(this.members[0].doc()) this.each(function() { // user rbox for correct position and visual representation - box = box.merge(this.rbox()) + rbox = rbox.merge(this.rbox(this.doc())) }) - return box + return rbox } } @@ -4985,8 +5286,6 @@ SVG.Set.inherit = function() { } - - SVG.extend(SVG.Element, { // Store data values on svg nodes data: function(a, v, r) { @@ -5073,6 +5372,22 @@ SVG.extend(SVG.Parent, { } }) +function pathRegReplace(a, b, c, d) { + return c + d.replace(SVG.regex.dots, ' .') +} + +// creates deep clone of array +function array_clone(arr){ + var clone = arr.slice(0) + for(var i = clone.length; i--;){ + if(Array.isArray(clone[i])){ + clone[i] = array_clone(clone[i]) + } + } + return clone +} + +// tests if a given element is instance of an object function is(el, obj){ return el instanceof obj } @@ -5111,11 +5426,15 @@ function compToHex(comp) { } // Calculate proportional width and height values when necessary -function proportionalSize(box, width, height) { - if (height == null) - height = box.height / box.width * width - else if (width == null) - width = box.width / box.height * height +function proportionalSize(element, width, height) { + if (width == null || height == null) { + var box = element.bbox() + + if (width == null) + width = box.width / box.height * height + else if (height == null) + height = box.height / box.width * width + } return { width: width @@ -5150,35 +5469,6 @@ function ensureCentre(o, target) { o.cy = o.cy == null ? target.bbox().cy : o.cy } -// Convert string to matrix -function stringToMatrix(source) { - // remove matrix wrapper and split to individual numbers - source = source - .replace(SVG.regex.whitespace, '') - .replace(SVG.regex.matrix, '') - .split(SVG.regex.matrixElements) - - // convert string values to floats and convert to a matrix-formatted object - return arrayToMatrix( - SVG.utils.map(source, function(n) { - return parseFloat(n) - }) - ) -} - -// Calculate position according to from and to -function at(o, pos) { - // number recalculation (don't bother converting to SVG.Number for performance reasons) - return typeof o.from == 'number' ? - o.from + (o.to - o.from) * pos : - - // instance recalculation - o instanceof SVG.Color || o instanceof SVG.Number || o instanceof SVG.Matrix ? o.at(pos) : - - // for all other values wait until pos has reached 1 to return the final value - pos < 1 ? o.from : o.to -} - // PathArray Helpers function arrayToString(a) { for (var i = 0, il = a.length, s = ''; i < il; i++) { @@ -5220,7 +5510,7 @@ function arrayToString(a) { function assignNewId(node) { // do the same for SVG child nodes as well for (var i = node.childNodes.length - 1; i >= 0; i--) - if (node.childNodes[i] instanceof SVGElement) + if (node.childNodes[i] instanceof window.SVGElement) assignNewId(node.childNodes[i]) return SVG.adopt(node).id(SVG.eid(node.nodeName)) @@ -5247,26 +5537,35 @@ function fullBox(b) { // Get id from reference string function idFromReference(url) { - var m = url.toString().match(SVG.regex.reference) + var m = (url || '').toString().match(SVG.regex.reference) if (m) return m[1] } +// If values like 1e-88 are passed, this is not a valid 32 bit float, +// but in those cases, we are so close to 0 that 0 works well! +function float32String(v) { + return Math.abs(v) > 1e-37 ? v : 0 +} + // Create matrix array for looping var abcdef = 'abcdef'.split('') + // Add CustomEvent to IE9 and IE10 -if (typeof CustomEvent !== 'function') { +if (typeof window.CustomEvent !== 'function') { // Code from: https://developer.mozilla.org/en-US/docs/Web/API/CustomEvent - var CustomEvent = function(event, options) { + var CustomEventPoly = function(event, options) { options = options || { bubbles: false, cancelable: false, detail: undefined } var e = document.createEvent('CustomEvent') e.initCustomEvent(event, options.bubbles, options.cancelable, options.detail) return e } - CustomEvent.prototype = window.Event.prototype + CustomEventPoly.prototype = window.Event.prototype - window.CustomEvent = CustomEvent + SVG.CustomEvent = CustomEventPoly +} else { + SVG.CustomEvent = window.CustomEvent } // requestAnimationFrame / cancelAnimationFrame Polyfill with fallback based on Paul Irish diff --git a/hal-core/resources/web/js/lib/svg.min.js b/hal-core/resources/web/js/lib/svg.min.js new file mode 100644 index 00000000..d4b36bd4 --- /dev/null +++ b/hal-core/resources/web/js/lib/svg.min.js @@ -0,0 +1,3 @@ +/*! svg.js v2.7.1 MIT*/;!function(t,e){"function"==typeof define&&define.amd?define(function(){return e(t,t.document)}):"object"==typeof exports?module.exports=t.document?e(t,t.document):function(t){return e(t,t.document)}:t.SVG=e(t,t.document)}("undefined"!=typeof window?window:this,function(t,e){function i(t,e,i,n){return i+n.replace(b.regex.dots," .")}function n(t){for(var e=t.slice(0),i=e.length;i--;)Array.isArray(e[i])&&(e[i]=n(e[i]));return e}function r(t,e){return t instanceof e}function s(t,e){return(t.matches||t.matchesSelector||t.msMatchesSelector||t.mozMatchesSelector||t.webkitMatchesSelector||t.oMatchesSelector).call(t,e)}function o(t){return t.toLowerCase().replace(/-(.)/g,function(t,e){return e.toUpperCase()})}function a(t){return t.charAt(0).toUpperCase()+t.slice(1)}function h(t){return 4==t.length?["#",t.substring(1,2),t.substring(1,2),t.substring(2,3),t.substring(2,3),t.substring(3,4),t.substring(3,4)].join(""):t}function u(t){var e=t.toString(16);return 1==e.length?"0"+e:e}function l(t,e,i){if(null==e||null==i){var n=t.bbox();null==e?e=n.width/n.height*i:null==i&&(i=n.height/n.width*e)}return{width:e,height:i}}function c(t,e,i){return{x:e*t.a+i*t.c+0,y:e*t.b+i*t.d+0}}function f(t){return{a:t[0],b:t[1],c:t[2],d:t[3],e:t[4],f:t[5]}}function d(t){return t instanceof b.Matrix||(t=new b.Matrix(t)),t}function p(t,e){t.cx=null==t.cx?e.bbox().cx:t.cx,t.cy=null==t.cy?e.bbox().cy:t.cy}function m(t){for(var e=0,i=t.length,n="";e=0;i--)e.childNodes[i]instanceof t.SVGElement&&x(e.childNodes[i]);return b.adopt(e).id(b.eid(e.nodeName))}function y(t){return null==t.x&&(t.x=0,t.y=0,t.width=0,t.height=0),t.w=t.width,t.h=t.height,t.x2=t.x+t.width,t.y2=t.y+t.height,t.cx=t.x+t.width/2,t.cy=t.y+t.height/2,t}function v(t){var e=(t||"").toString().match(b.regex.reference);if(e)return e[1]}function g(t){return Math.abs(t)>1e-37?t:0}var w=void 0!==this?this:t,b=w.SVG=function(t){if(b.supported)return t=new b.Doc(t),b.parser.draw||b.prepare(),t};if(b.ns="http://www.w3.org/2000/svg",b.xmlns="http://www.w3.org/2000/xmlns/",b.xlink="http://www.w3.org/1999/xlink",b.svgjs="http://svgjs.com/svgjs",b.supported=function(){return!!e.createElementNS&&!!e.createElementNS(b.ns,"svg").createSVGRect}(),!b.supported)return!1;b.did=1e3,b.eid=function(t){return"Svgjs"+a(t)+b.did++},b.create=function(t){var i=e.createElementNS(this.ns,t);return i.setAttribute("id",this.eid(t)),i},b.extend=function(){var t,e,i,n;for(t=[].slice.call(arguments),e=t.pop(),n=t.length-1;n>=0;n--)if(t[n])for(i in e)t[n].prototype[i]=e[i];b.Set&&b.Set.inherit&&b.Set.inherit()},b.invent=function(t){var e="function"==typeof t.create?t.create:function(){this.constructor.call(this,b.create(t.create))};return t.inherit&&(e.prototype=new t.inherit),t.extend&&b.extend(e,t.extend),t.construct&&b.extend(t.parent||b.Container,t.construct),e},b.adopt=function(e){if(!e)return null;if(e.instance)return e.instance;var i;return i="svg"==e.nodeName?e.parentNode instanceof t.SVGElement?new b.Nested:new b.Doc:"linearGradient"==e.nodeName?new b.Gradient("linear"):"radialGradient"==e.nodeName?new b.Gradient("radial"):b[a(e.nodeName)]?new(b[a(e.nodeName)]):new b.Element(e),i.type=e.nodeName,i.node=e,e.instance=i,i instanceof b.Doc&&i.namespace().defs(),i.setData(JSON.parse(e.getAttribute("svgjs:data"))||{}),i},b.prepare=function(){var t=e.getElementsByTagName("body")[0],i=(t?new b.Doc(t):b.adopt(e.documentElement).nested()).size(2,0);b.parser={body:t||e.documentElement,draw:i.style("opacity:0;position:absolute;left:-100%;top:-100%;overflow:hidden").attr("focusable","false").node,poly:i.polyline().node,path:i.path().node,native:b.create("svg")}},b.parser={native:b.create("svg")},e.addEventListener("DOMContentLoaded",function(){b.parser.draw||b.prepare()},!1),b.regex={numberAndUnit:/^([+-]?(\d+(\.\d*)?|\.\d+)(e[+-]?\d+)?)([a-z%]*)$/i,hex:/^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i,rgb:/rgb\((\d+),(\d+),(\d+)\)/,reference:/#([a-z0-9\-_]+)/i,transforms:/\)\s*,?\s*/,whitespace:/\s/g,isHex:/^#[a-f0-9]{3,6}$/i,isRgb:/^rgb\(/,isCss:/[^:]+:[^;]+;?/,isBlank:/^(\s+)?$/,isNumber:/^[+-]?(\d+(\.\d*)?|\.\d+)(e[+-]?\d+)?$/i,isPercent:/^-?[\d\.]+%$/,isImage:/\.(jpg|jpeg|png|gif|svg)(\?[^=]+.*)?/i,delimiter:/[\s,]+/,hyphen:/([^e])\-/gi,pathLetters:/[MLHVCSQTAZ]/gi,isPathLetter:/[MLHVCSQTAZ]/i,numbersWithDots:/((\d?\.\d+(?:e[+-]?\d+)?)((?:\.\d+(?:e[+-]?\d+)?)+))+/gi,dots:/\./g},b.utils={map:function(t,e){var i,n=t.length,r=[];for(i=0;i1?1:t,new b.Color({r:~~(this.r+(this.destination.r-this.r)*t),g:~~(this.g+(this.destination.g-this.g)*t),b:~~(this.b+(this.destination.b-this.b)*t)})):this}}),b.Color.test=function(t){return t+="",b.regex.isHex.test(t)||b.regex.isRgb.test(t)},b.Color.isRgb=function(t){return t&&"number"==typeof t.r&&"number"==typeof t.g&&"number"==typeof t.b},b.Color.isColor=function(t){return b.Color.isRgb(t)||b.Color.test(t)},b.Array=function(t,e){t=(t||[]).valueOf(),0==t.length&&e&&(t=e.valueOf()),this.value=this.parse(t)},b.extend(b.Array,{morph:function(t){if(this.destination=this.parse(t),this.value.length!=this.destination.length){for(var e=this.value[this.value.length-1],i=this.destination[this.destination.length-1];this.value.length>this.destination.length;)this.destination.push(i);for(;this.value.length=0;n--)this.value[n]=[this.value[n][0]+t,this.value[n][1]+e];return this},size:function(t,e){var i,n=this.bbox();for(i=this.value.length-1;i>=0;i--)n.width&&(this.value[i][0]=(this.value[i][0]-n.x)*t/n.width+n.x),n.height&&(this.value[i][1]=(this.value[i][1]-n.y)*e/n.height+n.y);return this},bbox:function(){return b.parser.poly.setAttribute("points",this.toString()),b.parser.poly.getBBox()}});for(var C={M:function(t,e,i){return e.x=i.x=t[0],e.y=i.y=t[1],["M",e.x,e.y]},L:function(t,e){return e.x=t[0],e.y=t[1],["L",t[0],t[1]]},H:function(t,e){return e.x=t[0],["H",t[0]]},V:function(t,e){return e.y=t[0],["V",t[0]]},C:function(t,e){return e.x=t[4],e.y=t[5],["C",t[0],t[1],t[2],t[3],t[4],t[5]]},S:function(t,e){return e.x=t[2],e.y=t[3],["S",t[0],t[1],t[2],t[3]]},Q:function(t,e){return e.x=t[2],e.y=t[3],["Q",t[0],t[1],t[2],t[3]]},T:function(t,e){return e.x=t[0],e.y=t[1],["T",t[0],t[1]]},Z:function(t,e,i){return e.x=i.x,e.y=i.y,["Z"]},A:function(t,e){return e.x=t[5],e.y=t[6],["A",t[0],t[1],t[2],t[3],t[4],t[5],t[6]]}},N="mlhvqtcsaz".split(""),A=0,P=N.length;A=0;r--)n=this.value[r][0],"M"==n||"L"==n||"T"==n?(this.value[r][1]+=t,this.value[r][2]+=e):"H"==n?this.value[r][1]+=t:"V"==n?this.value[r][1]+=e:"C"==n||"S"==n||"Q"==n?(this.value[r][1]+=t,this.value[r][2]+=e,this.value[r][3]+=t,this.value[r][4]+=e,"C"==n&&(this.value[r][5]+=t,this.value[r][6]+=e)):"A"==n&&(this.value[r][6]+=t,this.value[r][7]+=e);return this},size:function(t,e){var i,n,r=this.bbox();for(i=this.value.length-1;i>=0;i--)n=this.value[i][0],"M"==n||"L"==n||"T"==n?(this.value[i][1]=(this.value[i][1]-r.x)*t/r.width+r.x,this.value[i][2]=(this.value[i][2]-r.y)*e/r.height+r.y):"H"==n?this.value[i][1]=(this.value[i][1]-r.x)*t/r.width+r.x:"V"==n?this.value[i][1]=(this.value[i][1]-r.y)*e/r.height+r.y:"C"==n||"S"==n||"Q"==n?(this.value[i][1]=(this.value[i][1]-r.x)*t/r.width+r.x,this.value[i][2]=(this.value[i][2]-r.y)*e/r.height+r.y,this.value[i][3]=(this.value[i][3]-r.x)*t/r.width+r.x,this.value[i][4]=(this.value[i][4]-r.y)*e/r.height+r.y,"C"==n&&(this.value[i][5]=(this.value[i][5]-r.x)*t/r.width+r.x,this.value[i][6]=(this.value[i][6]-r.y)*e/r.height+r.y)):"A"==n&&(this.value[i][1]=this.value[i][1]*t/r.width,this.value[i][2]=this.value[i][2]*e/r.height,this.value[i][6]=(this.value[i][6]-r.x)*t/r.width+r.x,this.value[i][7]=(this.value[i][7]-r.y)*e/r.height+r.y);return this},equalCommands:function(t){var e,i,n;for(t=new b.PathArray(t),n=this.value.length===t.value.length,e=0,i=this.value.length;n&&ea);return n},bbox:function(){return b.parser.path.setAttribute("d",this.toString()),b.parser.path.getBBox()}}),b.Number=b.invent({create:function(t,e){this.value=0,this.unit=e||"","number"==typeof t?this.value=isNaN(t)?0:isFinite(t)?t:t<0?-3.4e38:3.4e38:"string"==typeof t?(e=t.match(b.regex.numberAndUnit))&&(this.value=parseFloat(e[1]),"%"==e[5]?this.value/=100:"s"==e[5]&&(this.value*=1e3),this.unit=e[5]):t instanceof b.Number&&(this.value=t.valueOf(),this.unit=t.unit)},extend:{toString:function(){return("%"==this.unit?~~(1e8*this.value)/1e6:"s"==this.unit?this.value/1e3:this.value)+this.unit},toJSON:function(){return this.toString()},valueOf:function(){return this.value},plus:function(t){return t=new b.Number(t),new b.Number(this+t,this.unit||t.unit)},minus:function(t){return t=new b.Number(t),new b.Number(this-t,this.unit||t.unit)},times:function(t){return t=new b.Number(t),new b.Number(this*t,this.unit||t.unit)},divide:function(t){return t=new b.Number(t),new b.Number(this/t,this.unit||t.unit)},to:function(t){var e=new b.Number(this);return"string"==typeof t&&(e.unit=t),e},morph:function(t){return this.destination=new b.Number(t),t.relative&&(this.destination.value+=this.value),this},at:function(t){return this.destination?new b.Number(this.destination).minus(this).times(t).plus(this):this}}}),b.Element=b.invent({create:function(t){this._stroke=b.defaults.attrs.stroke,this._event=null,this._events={},this.dom={},(this.node=t)&&(this.type=t.nodeName,this.node.instance=this,this._events=t._events||{},this._stroke=t.getAttribute("stroke")||this._stroke)},extend:{x:function(t){return this.attr("x",t)},y:function(t){return this.attr("y",t)},cx:function(t){return null==t?this.x()+this.width()/2:this.x(t-this.width()/2)},cy:function(t){return null==t?this.y()+this.height()/2:this.y(t-this.height()/2)},move:function(t,e){return this.x(t).y(e)},center:function(t,e){return this.cx(t).cy(e)},width:function(t){return this.attr("width",t)},height:function(t){return this.attr("height",t)},size:function(t,e){var i=l(this,t,e);return this.width(new b.Number(i.width)).height(new b.Number(i.height))},clone:function(t){this.writeDataToDom();var e=x(this.node.cloneNode(!0));return t?t.add(e):this.after(e),e},remove:function(){return this.parent()&&this.parent().removeElement(this),this},replace:function(t){return this.after(t).remove(),t},addTo:function(t){return t.put(this)},putIn:function(t){return t.add(this)},id:function(t){return this.attr("id",t)},inside:function(t,e){var i=this.bbox();return t>i.x&&e>i.y&&t/,"").replace(/<\/svg>$/,"");i.innerHTML=""+t.replace(/\n/,"").replace(/<([\w:-]+)([^<]+?)\/>/g,"<$1$2>")+"";for(var n=0,r=i.firstChild.childNodes.length;n":function(t){return-Math.cos(t*Math.PI)/2+.5},">":function(t){return Math.sin(t*Math.PI/2)},"<":function(t){return 1-Math.cos(t*Math.PI/2)}},b.morph=function(t){return function(e,i){return new b.MorphObj(e,i).at(t)}},b.Situation=b.invent({create:function(t){this.init=!1,this.reversed=!1,this.reversing=!1,this.duration=new b.Number(t.duration).valueOf(),this.delay=new b.Number(t.delay).valueOf(),this.start=+new Date+this.delay,this.finish=this.start+this.duration,this.ease=t.ease,this.loop=0,this.loops=!1,this.animations={},this.attrs={},this.styles={},this.transforms=[],this.once={}}}),b.FX=b.invent({create:function(t){this._target=t,this.situations=[],this.active=!1,this.situation=null,this.paused=!1,this.lastPos=0,this.pos=0,this.absPos=0,this._speed=1},extend:{animate:function(t,e,i){"object"==typeof t&&(e=t.ease,i=t.delay,t=t.duration);var n=new b.Situation({duration:t||1e3,delay:i||0,ease:b.easing[e||"-"]||e});return this.queue(n),this},delay:function(t){var e=new b.Situation({duration:t,delay:0,ease:b.easing["-"]});return this.queue(e)},target:function(t){return t&&t instanceof b.Element?(this._target=t,this):this._target},timeToAbsPos:function(t){return(t-this.situation.start)/(this.situation.duration/this._speed)},absPosToTime:function(t){return this.situation.duration/this._speed*t+this.situation.start},startAnimFrame:function(){this.stopAnimFrame(),this.animationFrame=t.requestAnimationFrame(function(){this.step()}.bind(this))},stopAnimFrame:function(){t.cancelAnimationFrame(this.animationFrame)},start:function(){return!this.active&&this.situation&&(this.active=!0,this.startCurrent()),this},startCurrent:function(){return this.situation.start=+new Date+this.situation.delay/this._speed,this.situation.finish=this.situation.start+this.situation.duration/this._speed,this.initAnimations().step()},queue:function(t){return("function"==typeof t||t instanceof b.Situation)&&this.situations.push(t),this.situation||(this.situation=this.situations.shift()),this},dequeue:function(){return this.stop(),this.situation=this.situations.shift(),this.situation&&(this.situation instanceof b.Situation?this.start():this.situation.call(this)),this},initAnimations:function(){var t,e,i,n=this.situation;if(n.init)return this;for(t in n.animations)for(i=this.target()[t](),Array.isArray(i)||(i=[i]),Array.isArray(n.animations[t])||(n.animations[t]=[n.animations[t]]),e=i.length;e--;)n.animations[t][e]instanceof b.Number&&(i[e]=new b.Number(i[e])),n.animations[t][e]=i[e].morph(n.animations[t][e]);for(t in n.attrs)n.attrs[t]=new b.MorphObj(this.target().attr(t),n.attrs[t]);for(t in n.styles)n.styles[t]=new b.MorphObj(this.target().style(t),n.styles[t]);return n.initialTransformation=this.target().matrixify(),n.init=!0,this},clearQueue:function(){return this.situations=[],this},clearCurrent:function(){return this.situation=null,this},stop:function(t,e){var i=this.active;return this.active=!1,e&&this.clearQueue(),t&&this.situation&&(!i&&this.startCurrent(),this.atEnd()),this.stopAnimFrame(),this.clearCurrent()},reset:function(){if(this.situation){var t=this.situation;this.stop(),this.situation=t,this.atStart()}return this},finish:function(){for(this.stop(!0,!1);this.dequeue().situation&&this.stop(!0,!1););return this.clearQueue().clearCurrent(),this},atStart:function(){return this.at(0,!0)},atEnd:function(){return!0===this.situation.loops&&(this.situation.loops=this.situation.loop+1),"number"==typeof this.situation.loops?this.at(this.situation.loops,!0):this.at(1,!0)},at:function(t,e){var i=this.situation.duration/this._speed;return this.absPos=t,e||(this.situation.reversed&&(this.absPos=1-this.absPos),this.absPos+=this.situation.loop),this.situation.start=+new Date-this.absPos*i,this.situation.finish=this.situation.start+i,this.step(!0)},speed:function(t){return 0===t?this.pause():t?(this._speed=t,this.at(this.absPos,!0)):this._speed},loop:function(t,e){var i=this.last();return i.loops=null==t||t,i.loop=0,e&&(i.reversing=!0),this},pause:function(){return this.paused=!0,this.stopAnimFrame(),this},play:function(){return this.paused?(this.paused=!1,this.at(this.absPos,!0)):this},reverse:function(t){var e=this.last();return e.reversed=void 0===t?!e.reversed:t,this},progress:function(t){return t?this.situation.ease(this.pos):this.pos},after:function(t){var e=this.last(),i=function i(n){n.detail.situation==e&&(t.call(this,e),this.off("finished.fx",i))};return this.target().on("finished.fx",i),this._callStart()},during:function(t){var e=this.last(),i=function(i){i.detail.situation==e&&t.call(this,i.detail.pos,b.morph(i.detail.pos),i.detail.eased,e)};return this.target().off("during.fx",i).on("during.fx",i),this.after(function(){this.off("during.fx",i)}),this._callStart()},afterAll:function(t){var e=function e(i){t.call(this),this.off("allfinished.fx",e)};return this.target().off("allfinished.fx",e).on("allfinished.fx",e),this._callStart()},duringAll:function(t){var e=function(e){t.call(this,e.detail.pos,b.morph(e.detail.pos),e.detail.eased,e.detail.situation)};return this.target().off("during.fx",e).on("during.fx",e),this.afterAll(function(){this.off("during.fx",e)}),this._callStart()},last:function(){return this.situations.length?this.situations[this.situations.length-1]:this.situation},add:function(t,e,i){return this.last()[i||"animations"][t]=e,this._callStart()},step:function(t){if(t||(this.absPos=this.timeToAbsPos(+new Date)),!1!==this.situation.loops){var e,i,n;e=Math.max(this.absPos,0),i=Math.floor(e),!0===this.situation.loops||ithis.lastPos&&s<=r&&(this.situation.once[s].call(this.target(),this.pos,r),delete this.situation.once[s]);return this.active&&this.target().fire("during",{pos:this.pos,eased:r,fx:this,situation:this.situation}),this.situation?(this.eachAt(),1==this.pos&&!this.situation.reversed||this.situation.reversed&&0==this.pos?(this.stopAnimFrame(),this.target().fire("finished",{fx:this,situation:this.situation}),this.situations.length||(this.target().fire("allfinished"),this.situations.length||(this.target().off(".fx"),this.active=!1)),this.active?this.dequeue():this.clearCurrent()):!this.paused&&this.active&&this.startAnimFrame(),this.lastPos=r,this):this},eachAt:function(){var t,e,i,n=this,r=this.target(),s=this.situation;for(t in s.animations)i=[].concat(s.animations[t]).map(function(t){return"string"!=typeof t&&t.at?t.at(s.ease(n.pos),n.pos):t}),r[t].apply(r,i);for(t in s.attrs)i=[t].concat(s.attrs[t]).map(function(t){return"string"!=typeof t&&t.at?t.at(s.ease(n.pos),n.pos):t}),r.attr.apply(r,i);for(t in s.styles)i=[t].concat(s.styles[t]).map(function(t){return"string"!=typeof t&&t.at?t.at(s.ease(n.pos),n.pos):t}),r.style.apply(r,i);if(s.transforms.length){for(i=s.initialTransformation,t=0,e=s.transforms.length;t=0;--e)this[k[e]]=null!=t[k[e]]?t[k[e]]:i[k[e]]},extend:{extract:function(){var t=c(this,0,1),e=c(this,1,0),i=180/Math.PI*Math.atan2(t.y,t.x)-90;return{x:this.e,y:this.f,transformedX:(this.e*Math.cos(i*Math.PI/180)+this.f*Math.sin(i*Math.PI/180))/Math.sqrt(this.a*this.a+this.b*this.b),transformedY:(this.f*Math.cos(i*Math.PI/180)+this.e*Math.sin(-i*Math.PI/180))/Math.sqrt(this.c*this.c+this.d*this.d),skewX:-i,skewY:180/Math.PI*Math.atan2(e.y,e.x),scaleX:Math.sqrt(this.a*this.a+this.b*this.b),scaleY:Math.sqrt(this.c*this.c+this.d*this.d),rotation:i,a:this.a,b:this.b,c:this.c,d:this.d,e:this.e,f:this.f,matrix:new b.Matrix(this)}},clone:function(){return new b.Matrix(this)},morph:function(t){return this.destination=new b.Matrix(t),this},at:function(t){return this.destination?new b.Matrix({a:this.a+(this.destination.a-this.a)*t,b:this.b+(this.destination.b-this.b)*t,c:this.c+(this.destination.c-this.c)*t,d:this.d+(this.destination.d-this.d)*t,e:this.e+(this.destination.e-this.e)*t,f:this.f+(this.destination.f-this.f)*t}):this},multiply:function(t){return new b.Matrix(this.native().multiply(d(t).native()))},inverse:function(){return new b.Matrix(this.native().inverse())},translate:function(t,e){return new b.Matrix(this.native().translate(t||0,e||0))},scale:function(t,e,i,n){return 1==arguments.length?e=t:3==arguments.length&&(n=i,i=e,e=t),this.around(i,n,new b.Matrix(t,0,0,e,0,0))},rotate:function(t,e,i){return t=b.utils.radians(t),this.around(e,i,new b.Matrix(Math.cos(t),Math.sin(t),-Math.sin(t),Math.cos(t),0,0))},flip:function(t,e){return"x"==t?this.scale(-1,1,e,0):"y"==t?this.scale(1,-1,0,e):this.scale(-1,-1,t,null!=e?e:t)},skew:function(t,e,i,n){ +return 1==arguments.length?e=t:3==arguments.length&&(n=i,i=e,e=t),t=b.utils.radians(t),e=b.utils.radians(e),this.around(i,n,new b.Matrix(1,Math.tan(e),Math.tan(t),1,0,0))},skewX:function(t,e,i){return this.skew(t,0,e,i)},skewY:function(t,e,i){return this.skew(0,t,e,i)},around:function(t,e,i){return this.multiply(new b.Matrix(1,0,0,1,t||0,e||0)).multiply(i).multiply(new b.Matrix(1,0,0,1,-t||0,-e||0))},native:function(){for(var t=b.parser.native.createSVGMatrix(),e=k.length-1;e>=0;e--)t[k[e]]=this[k[e]];return t},toString:function(){return"matrix("+g(this.a)+","+g(this.b)+","+g(this.c)+","+g(this.d)+","+g(this.e)+","+g(this.f)+")"}},parent:b.Element,construct:{ctm:function(){return new b.Matrix(this.node.getCTM())},screenCTM:function(){if(this instanceof b.Nested){var t=this.rect(1,1),e=t.node.getScreenCTM();return t.remove(),new b.Matrix(e)}return new b.Matrix(this.node.getScreenCTM())}}}),b.Point=b.invent({create:function(t,e){var i,n={x:0,y:0};i=Array.isArray(t)?{x:t[0],y:t[1]}:"object"==typeof t?{x:t.x,y:t.y}:null!=t?{x:t,y:null!=e?e:t}:n,this.x=i.x,this.y=i.y},extend:{clone:function(){return new b.Point(this)},morph:function(t,e){return this.destination=new b.Point(t,e),this},at:function(t){return this.destination?new b.Point({x:this.x+(this.destination.x-this.x)*t,y:this.y+(this.destination.y-this.y)*t}):this},native:function(){var t=b.parser.native.createSVGPoint();return t.x=this.x,t.y=this.y,t},transform:function(t){return new b.Point(this.native().matrixTransform(t.native()))}}}),b.extend(b.Element,{point:function(t,e){return new b.Point(t,e).transform(this.screenCTM().inverse())}}),b.extend(b.Element,{attr:function(t,e,i){if(null==t){for(t={},e=this.node.attributes,i=e.length-1;i>=0;i--)t[e[i].nodeName]=b.regex.isNumber.test(e[i].nodeValue)?parseFloat(e[i].nodeValue):e[i].nodeValue;return t}if("object"==typeof t)for(e in t)this.attr(e,t[e]);else if(null===e)this.node.removeAttribute(t);else{if(null==e)return e=this.node.getAttribute(t),null==e?b.defaults.attrs[t]:b.regex.isNumber.test(e)?parseFloat(e):e;"stroke-width"==t?this.attr("stroke",parseFloat(e)>0?this._stroke:null):"stroke"==t&&(this._stroke=e),"fill"!=t&&"stroke"!=t||(b.regex.isImage.test(e)&&(e=this.doc().defs().image(e,0,0)),e instanceof b.Image&&(e=this.doc().defs().pattern(0,0,function(){this.add(e)}))),"number"==typeof e?e=new b.Number(e):b.Color.isColor(e)?e=new b.Color(e):Array.isArray(e)&&(e=new b.Array(e)),"leading"==t?this.leading&&this.leading(e):"string"==typeof i?this.node.setAttributeNS(i,t,e.toString()):this.node.setAttribute(t,e.toString()),!this.rebuild||"font-size"!=t&&"x"!=t||this.rebuild(t,e)}return this}}),b.extend(b.Element,{transform:function(t,e){var i,n,r=this;if("object"!=typeof t)return i=new b.Matrix(r).extract(),"string"==typeof t?i[t]:i;if(i=new b.Matrix(r),e=!!e||!!t.relative,null!=t.a)i=e?i.multiply(new b.Matrix(t)):new b.Matrix(t);else if(null!=t.rotation)p(t,r),i=e?i.rotate(t.rotation,t.cx,t.cy):i.rotate(t.rotation-i.extract().rotation,t.cx,t.cy);else if(null!=t.scale||null!=t.scaleX||null!=t.scaleY){if(p(t,r),t.scaleX=null!=t.scale?t.scale:null!=t.scaleX?t.scaleX:1,t.scaleY=null!=t.scale?t.scale:null!=t.scaleY?t.scaleY:1,!e){var s=i.extract();t.scaleX=1*t.scaleX/s.scaleX,t.scaleY=1*t.scaleY/s.scaleY}i=i.scale(t.scaleX,t.scaleY,t.cx,t.cy)}else if(null!=t.skew||null!=t.skewX||null!=t.skewY){if(p(t,r),t.skewX=null!=t.skew?t.skew:null!=t.skewX?t.skewX:0,t.skewY=null!=t.skew?t.skew:null!=t.skewY?t.skewY:0,!e){var s=i.extract();i=i.multiply((new b.Matrix).skew(s.skewX,s.skewY,t.cx,t.cy).inverse())}i=i.skew(t.skewX,t.skewY,t.cx,t.cy)}else t.flip?("x"==t.flip||"y"==t.flip?t.offset=null==t.offset?r.bbox()["c"+t.flip]:t.offset:null==t.offset?(n=r.bbox(),t.flip=n.cx,t.offset=n.cy):t.flip=t.offset,i=(new b.Matrix).flip(t.flip,t.offset)):null==t.x&&null==t.y||(e?i=i.translate(t.x,t.y):(null!=t.x&&(i.e=t.x),null!=t.y&&(i.f=t.y)));return this.attr("transform",i)}}),b.extend(b.FX,{transform:function(t,e){var i,n,r=this.target();return"object"!=typeof t?(i=new b.Matrix(r).extract(),"string"==typeof t?i[t]:i):(e=!!e||!!t.relative,null!=t.a?i=new b.Matrix(t):null!=t.rotation?(p(t,r),i=new b.Rotate(t.rotation,t.cx,t.cy)):null!=t.scale||null!=t.scaleX||null!=t.scaleY?(p(t,r),t.scaleX=null!=t.scale?t.scale:null!=t.scaleX?t.scaleX:1,t.scaleY=null!=t.scale?t.scale:null!=t.scaleY?t.scaleY:1,i=new b.Scale(t.scaleX,t.scaleY,t.cx,t.cy)):null!=t.skewX||null!=t.skewY?(p(t,r),t.skewX=null!=t.skewX?t.skewX:0,t.skewY=null!=t.skewY?t.skewY:0,i=new b.Skew(t.skewX,t.skewY,t.cx,t.cy)):t.flip?("x"==t.flip||"y"==t.flip?t.offset=null==t.offset?r.bbox()["c"+t.flip]:t.offset:null==t.offset?(n=r.bbox(),t.flip=n.cx,t.offset=n.cy):t.flip=t.offset,i=(new b.Matrix).flip(t.flip,t.offset)):null==t.x&&null==t.y||(i=new b.Translate(t.x,t.y)),i?(i.relative=e,this.last().transforms.push(i),this._callStart()):this)}}),b.extend(b.Element,{untransform:function(){return this.attr("transform",null)},matrixify:function(){return(this.attr("transform")||"").split(b.regex.transforms).slice(0,-1).map(function(t){var e=t.trim().split("(");return[e[0],e[1].split(b.regex.delimiter).map(function(t){return parseFloat(t)})]}).reduce(function(t,e){return"matrix"==e[0]?t.multiply(f(e[1])):t[e[0]].apply(t,e[1])},new b.Matrix)},toParent:function(t){if(this==t)return this;var e=this.screenCTM(),i=t.screenCTM().inverse();return this.addTo(t).untransform().transform(i.multiply(e)),this},toDoc:function(){return this.toParent(this.doc())}}),b.Transformation=b.invent({create:function(t,e){if(arguments.length>1&&"boolean"!=typeof e)return this.constructor.call(this,[].slice.call(arguments));if(Array.isArray(t))for(var i=0,n=this.arguments.length;i=0},index:function(t){return[].slice.call(this.node.childNodes).indexOf(t.node)},get:function(t){return b.adopt(this.node.childNodes[t])},first:function(){return this.get(0)},last:function(){return this.get(this.node.childNodes.length-1)},each:function(t,e){var i,n,r=this.children();for(i=0,n=r.length;in/r?this.height/r:this.width/n,this.x=e,this.y=i,this.width=n,this.height=r)}else t="string"==typeof t?t.match(c).map(function(t){return parseFloat(t)}):Array.isArray(t)?t:"object"==typeof t?[t.x,t.y,t.width,t.height]:4==arguments.length?[].slice.call(arguments):h,this.x=t[0],this.y=t[1],this.width=t[2],this.height=t[3]},extend:{toString:function(){return this.x+" "+this.y+" "+this.width+" "+this.height},morph:function(t,e,i,n){return this.destination=new b.ViewBox(t,e,i,n),this},at:function(t){return this.destination?new b.ViewBox([this.x+(this.destination.x-this.x)*t,this.y+(this.destination.y-this.y)*t,this.width+(this.destination.width-this.width)*t,this.height+(this.destination.height-this.height)*t]):this}},parent:b.Container,construct:{viewbox:function(t,e,i,n){return 0==arguments.length?new b.ViewBox(this):this.attr("viewBox",new b.ViewBox(t,e,i,n))}}}),["click","dblclick","mousedown","mouseup","mouseover","mouseout","mousemove","mouseenter","mouseleave","touchstart","touchmove","touchleave","touchend","touchcancel"].forEach(function(t){b.Element.prototype[t]=function(e){return null==e?b.off(this,t):b.on(this,t,e),this}}),b.listenerId=0,b.on=function(t,e,i,n,r){var s=i.bind(n||t),o=t instanceof b.Element?t.node:t;o.instance=o.instance||{_events:{}};var a=o.instance._events;i._svgjsListenerId||(i._svgjsListenerId=++b.listenerId),e.split(b.regex.delimiter).forEach(function(t){var e=t.split(".")[0],n=t.split(".")[1]||"*";a[e]=a[e]||{},a[e][n]=a[e][n]||{},a[e][n][i._svgjsListenerId]=s,o.addEventListener(e,s,r||!1)})},b.off=function(t,e,i,n){var r=t instanceof b.Element?t.node:t;if(r.instance&&("function"!=typeof i||(i=i._svgjsListenerId))){var s=r.instance._events;(e||"").split(b.regex.delimiter).forEach(function(t){var e,o,a=t&&t.split(".")[0],h=t&&t.split(".")[1];if(i)s[a]&&s[a][h||"*"]&&(r.removeEventListener(a,s[a][h||"*"][i],n||!1),delete s[a][h||"*"][i]);else if(a&&h){if(s[a]&&s[a][h]){for(o in s[a][h])b.off(r,[a,h].join("."),o);delete s[a][h]}}else if(h)for(t in s)for(e in s[t])h===e&&b.off(r,[t,h].join("."));else if(a){if(s[a]){for(e in s[a])b.off(r,[a,e].join("."));delete s[a]}}else{for(t in s)b.off(r,t);r.instance._events={}}})}},b.extend(b.Element,{on:function(t,e,i,n){return b.on(this,t,e,i,n),this},off:function(t,e){return b.off(this.node,t,e),this},fire:function(e,i){return e instanceof t.Event?this.node.dispatchEvent(e):this.node.dispatchEvent(e=new b.CustomEvent(e,{detail:i,cancelable:!0})),this._event=e,this},event:function(){return this._event}}),b.Defs=b.invent({create:"defs",inherit:b.Container}),b.G=b.invent({create:"g",inherit:b.Container,extend:{x:function(t){return null==t?this.transform("x"):this.transform({x:t-this.x()},!0)},y:function(t){return null==t?this.transform("y"):this.transform({y:t-this.y()},!0)},cx:function(t){return null==t?this.gbox().cx:this.x(t-this.gbox().width/2)},cy:function(t){return null==t?this.gbox().cy:this.y(t-this.gbox().height/2)},gbox:function(){var t=this.bbox(),e=this.transform();return t.x+=e.x,t.x2+=e.x,t.cx+=e.x,t.y+=e.y,t.y2+=e.y,t.cy+=e.y,t}},construct:{group:function(){return this.put(new b.G)}}}),b.Doc=b.invent({create:function(t){t&&(t="string"==typeof t?e.getElementById(t):t,"svg"==t.nodeName?this.constructor.call(this,t):(this.constructor.call(this,b.create("svg")),t.appendChild(this.node),this.size("100%","100%")),this.namespace().defs())},inherit:b.Container,extend:{namespace:function(){return this.attr({xmlns:b.ns,version:"1.1"}).attr("xmlns:xlink",b.xlink,b.xmlns).attr("xmlns:svgjs",b.svgjs,b.xmlns)},defs:function(){if(!this._defs){var t;(t=this.node.getElementsByTagName("defs")[0])?this._defs=b.adopt(t):this._defs=new b.Defs,this.node.appendChild(this._defs.node)}return this._defs},parent:function(){return this.node.parentNode&&"#document"!=this.node.parentNode.nodeName&&"#document-fragment"!=this.node.parentNode.nodeName?this.node.parentNode:null},spof:function(){var t=this.node.getScreenCTM();return t&&this.style("left",-t.e%1+"px").style("top",-t.f%1+"px"),this},remove:function(){return this.parent()&&this.parent().removeChild(this.node),this},clear:function(){for(;this.node.hasChildNodes();)this.node.removeChild(this.node.lastChild);return delete this._defs,b.parser.draw.parentNode||this.node.appendChild(b.parser.draw),this},clone:function(t){this.writeDataToDom();var e=this.node,i=x(e.cloneNode(!0));return t?(t.node||t).appendChild(i.node):e.parentNode.insertBefore(i.node,e.nextSibling),i}}}),b.extend(b.Element,{siblings:function(){return this.parent().children()},position:function(){return this.parent().index(this)},next:function(){return this.siblings()[this.position()+1]},previous:function(){return this.siblings()[this.position()-1]},forward:function(){var t=this.position()+1,e=this.parent();return e.removeElement(this).add(this,t),e instanceof b.Doc&&e.node.appendChild(e.defs().node),this},backward:function(){var t=this.position();return t>0&&this.parent().removeElement(this).add(this,t-1),this},front:function(){var t=this.parent();return t.node.appendChild(this.node),t instanceof b.Doc&&t.node.appendChild(t.defs().node),this},back:function(){return this.position()>0&&this.parent().removeElement(this).add(this,0),this},before:function(t){t.remove();var e=this.position();return this.parent().add(t,e),this},after:function(t){t.remove();var e=this.position();return this.parent().add(t,e+1),this}}),b.Mask=b.invent({create:function(){this.constructor.call(this,b.create("mask")),this.targets=[]},inherit:b.Container,extend:{remove:function(){for(var t=this.targets.length-1;t>=0;t--)this.targets[t]&&this.targets[t].unmask();return this.targets=[],b.Element.prototype.remove.call(this),this}},construct:{mask:function(){return this.defs().put(new b.Mask)}}}),b.extend(b.Element,{maskWith:function(t){return this.masker=t instanceof b.Mask?t:this.parent().mask().add(t),this.masker.targets.push(this),this.attr("mask",'url("#'+this.masker.attr("id")+'")')},unmask:function(){return delete this.masker,this.attr("mask",null)}}),b.ClipPath=b.invent({create:function(){this.constructor.call(this,b.create("clipPath")),this.targets=[]},inherit:b.Container,extend:{remove:function(){for(var t=this.targets.length-1;t>=0;t--)this.targets[t]&&this.targets[t].unclip();return this.targets=[],this.parent().removeElement(this),this}},construct:{clip:function(){return this.defs().put(new b.ClipPath)}}}),b.extend(b.Element,{clipWith:function(t){return this.clipper=t instanceof b.ClipPath?t:this.parent().clip().add(t),this.clipper.targets.push(this),this.attr("clip-path",'url("#'+this.clipper.attr("id")+'")')},unclip:function(){return delete this.clipper,this.attr("clip-path",null)}}),b.Gradient=b.invent({create:function(t){this.constructor.call(this,b.create(t+"Gradient")),this.type=t},inherit:b.Container,extend:{at:function(t,e,i){return this.put(new b.Stop).update(t,e,i)},update:function(t){return this.clear(),"function"==typeof t&&t.call(this,this),this},fill:function(){return"url(#"+this.id()+")"},toString:function(){return this.fill()},attr:function(t,e,i){return"transform"==t&&(t="gradientTransform"),b.Container.prototype.attr.call(this,t,e,i)}},construct:{gradient:function(t,e){return this.defs().gradient(t,e)}}}),b.extend(b.Gradient,b.FX,{from:function(t,e){return"radial"==(this._target||this).type?this.attr({fx:new b.Number(t),fy:new b.Number(e)}):this.attr({x1:new b.Number(t),y1:new b.Number(e)})},to:function(t,e){return"radial"==(this._target||this).type?this.attr({cx:new b.Number(t),cy:new b.Number(e)}):this.attr({x2:new b.Number(t),y2:new b.Number(e)})}}),b.extend(b.Defs,{gradient:function(t,e){return this.put(new b.Gradient(t)).update(e)}}),b.Stop=b.invent({create:"stop",inherit:b.Element,extend:{update:function(t){return("number"==typeof t||t instanceof b.Number)&&(t={offset:arguments[0],color:arguments[1],opacity:arguments[2]}),null!=t.opacity&&this.attr("stop-opacity",t.opacity),null!=t.color&&this.attr("stop-color",t.color),null!=t.offset&&this.attr("offset",new b.Number(t.offset)),this}}}),b.Pattern=b.invent({create:"pattern",inherit:b.Container,extend:{fill:function(){return"url(#"+this.id()+")"},update:function(t){return this.clear(),"function"==typeof t&&t.call(this,this),this},toString:function(){return this.fill()},attr:function(t,e,i){return"transform"==t&&(t="patternTransform"),b.Container.prototype.attr.call(this,t,e,i)}},construct:{pattern:function(t,e,i){return this.defs().pattern(t,e,i)}}}),b.extend(b.Defs,{pattern:function(t,e,i){return this.put(new b.Pattern).update(i).attr({x:0,y:0,width:t,height:e,patternUnits:"userSpaceOnUse"})}}),b.Shape=b.invent({create:function(t){this.constructor.call(this,t)},inherit:b.Element}),b.Bare=b.invent({create:function(t,e){if(this.constructor.call(this,b.create(t)),e)for(var i in e.prototype)"function"==typeof e.prototype[i]&&(this[i]=e.prototype[i])},inherit:b.Element,extend:{words:function(t){for(;this.node.hasChildNodes();)this.node.removeChild(this.node.lastChild);return this.node.appendChild(e.createTextNode(t)),this}}}),b.extend(b.Parent,{element:function(t,e){return this.put(new b.Bare(t,e))}}),b.Symbol=b.invent({create:"symbol",inherit:b.Container,construct:{symbol:function(){return this.put(new b.Symbol)}}}),b.Use=b.invent({create:"use",inherit:b.Shape,extend:{element:function(t,e){return this.attr("href",(e||"")+"#"+t,b.xlink)}},construct:{use:function(t,e){return this.put(new b.Use).element(t,e)}}}),b.Rect=b.invent({create:"rect",inherit:b.Shape,construct:{rect:function(t,e){return this.put(new b.Rect).size(t,e)}}}),b.Circle=b.invent({create:"circle",inherit:b.Shape,construct:{circle:function(t){return this.put(new b.Circle).rx(new b.Number(t).divide(2)).move(0,0)}}}),b.extend(b.Circle,b.FX,{rx:function(t){return this.attr("r",t)},ry:function(t){return this.rx(t)}}),b.Ellipse=b.invent({create:"ellipse",inherit:b.Shape,construct:{ellipse:function(t,e){return this.put(new b.Ellipse).size(t,e).move(0,0)}}}),b.extend(b.Ellipse,b.Rect,b.FX,{rx:function(t){return this.attr("rx",t)},ry:function(t){return this.attr("ry",t)}}),b.extend(b.Circle,b.Ellipse,{x:function(t){return null==t?this.cx()-this.rx():this.cx(t+this.rx())},y:function(t){return null==t?this.cy()-this.ry():this.cy(t+this.ry())},cx:function(t){return null==t?this.attr("cx"):this.attr("cx",t)},cy:function(t){return null==t?this.attr("cy"):this.attr("cy",t)},width:function(t){return null==t?2*this.rx():this.rx(new b.Number(t).divide(2))},height:function(t){return null==t?2*this.ry():this.ry(new b.Number(t).divide(2))},size:function(t,e){var i=l(this,t,e);return this.rx(new b.Number(i.width).divide(2)).ry(new b.Number(i.height).divide(2))}}),b.Line=b.invent({create:"line",inherit:b.Shape,extend:{array:function(){return new b.PointArray([[this.attr("x1"),this.attr("y1")],[this.attr("x2"),this.attr("y2")]])},plot:function(t,e,i,n){return null==t?this.array():(t=void 0!==e?{x1:t,y1:e,x2:i,y2:n}:new b.PointArray(t).toLine(),this.attr(t))},move:function(t,e){return this.attr(this.array().move(t,e).toLine())},size:function(t,e){var i=l(this,t,e);return this.attr(this.array().size(i.width,i.height).toLine())}},construct:{line:function(t,e,i,n){return b.Line.prototype.plot.apply(this.put(new b.Line),null!=t?[t,e,i,n]:[0,0,0,0])}}}),b.Polyline=b.invent({create:"polyline",inherit:b.Shape,construct:{polyline:function(t){return this.put(new b.Polyline).plot(t||new b.PointArray)}}}),b.Polygon=b.invent({create:"polygon",inherit:b.Shape,construct:{polygon:function(t){return this.put(new b.Polygon).plot(t||new b.PointArray)}}}),b.extend(b.Polyline,b.Polygon,{array:function(){return this._array||(this._array=new b.PointArray(this.attr("points")))},plot:function(t){return null==t?this.array():this.clear().attr("points","string"==typeof t?t:this._array=new b.PointArray(t))},clear:function(){return delete this._array,this},move:function(t,e){return this.attr("points",this.array().move(t,e))},size:function(t,e){var i=l(this,t,e);return this.attr("points",this.array().size(i.width,i.height))}}),b.extend(b.Line,b.Polyline,b.Polygon,{morphArray:b.PointArray,x:function(t){return null==t?this.bbox().x:this.move(t,this.bbox().y)},y:function(t){return null==t?this.bbox().y:this.move(this.bbox().x,t)},width:function(t){var e=this.bbox();return null==t?e.width:this.size(t,e.height)},height:function(t){var e=this.bbox();return null==t?e.height:this.size(e.width,t)}}),b.Path=b.invent({create:"path",inherit:b.Shape,extend:{morphArray:b.PathArray,array:function(){return this._array||(this._array=new b.PathArray(this.attr("d")))},plot:function(t){return null==t?this.array():this.clear().attr("d","string"==typeof t?t:this._array=new b.PathArray(t))},clear:function(){return delete this._array,this},move:function(t,e){return this.attr("d",this.array().move(t,e))},x:function(t){return null==t?this.bbox().x:this.move(t,this.bbox().y)},y:function(t){return null==t?this.bbox().y:this.move(this.bbox().x,t)},size:function(t,e){var i=l(this,t,e);return this.attr("d",this.array().size(i.width,i.height))},width:function(t){return null==t?this.bbox().width:this.size(t,this.bbox().height)},height:function(t){return null==t?this.bbox().height:this.size(this.bbox().width,t)}},construct:{path:function(t){return this.put(new b.Path).plot(t||new b.PathArray)}}}),b.Image=b.invent({create:"image",inherit:b.Shape,extend:{load:function(e){if(!e)return this;var i=this,n=new t.Image;return b.on(n,"load",function(){b.off(n);var t=i.parent(b.Pattern);null!==t&&(0==i.width()&&0==i.height()&&i.size(n.width,n.height),t&&0==t.width()&&0==t.height()&&t.size(i.width(),i.height()),"function"==typeof i._loaded&&i._loaded.call(i,{width:n.width,height:n.height,ratio:n.width/n.height,url:e}))}),b.on(n,"error",function(t){b.off(n),"function"==typeof i._error&&i._error.call(i,t)}),this.attr("href",n.src=this.src=e,b.xlink)},loaded:function(t){return this._loaded=t,this},error:function(t){return this._error=t,this}},construct:{image:function(t,e,i){return this.put(new b.Image).load(t).size(e||0,i||e||0)}}}),b.Text=b.invent({create:function(){this.constructor.call(this,b.create("text")),this.dom.leading=new b.Number(1.3),this._rebuild=!0,this._build=!1,this.attr("font-family",b.defaults.attrs["font-family"])},inherit:b.Shape,extend:{x:function(t){return null==t?this.attr("x"):this.attr("x",t)},y:function(t){var e=this.attr("y"),i="number"==typeof e?e-this.bbox().y:0;return null==t?"number"==typeof e?e-i:e:this.attr("y","number"==typeof t.valueOf()?t+i:t)},cx:function(t){return null==t?this.bbox().cx:this.x(t-this.bbox().width/2)},cy:function(t){return null==t?this.bbox().cy:this.y(t-this.bbox().height/2)},text:function(t){if(void 0===t){for(var t="",e=this.node.childNodes,i=0,n=e.length;i=0;e--)null!=i[M[t][e]]&&this.attr(M.prefix(t,M[t][e]),i[M[t][e]]);return this},b.extend(b.Element,b.FX,i)}),b.extend(b.Element,b.FX,{rotate:function(t,e,i){return this.transform({rotation:t,cx:e,cy:i})},skew:function(t,e,i,n){return 1==arguments.length||3==arguments.length?this.transform({skew:t,cx:e,cy:i}):this.transform({skewX:t,skewY:e,cx:i,cy:n})},scale:function(t,e,i,n){return 1==arguments.length||3==arguments.length?this.transform({scale:t,cx:e,cy:i}):this.transform({scaleX:t,scaleY:e,cx:i,cy:n})},translate:function(t,e){return this.transform({x:t,y:e})},flip:function(t,e){return e="number"==typeof t?t:e,this.transform({flip:t||"both",offset:e})},matrix:function(t){return this.attr("transform",new b.Matrix(6==arguments.length?[].slice.call(arguments):t))},opacity:function(t){return this.attr("opacity",t)},dx:function(t){return this.x(new b.Number(t).plus(this instanceof b.FX?0:this.x()),!0)},dy:function(t){return this.y(new b.Number(t).plus(this instanceof b.FX?0:this.y()),!0)},dmove:function(t,e){return this.dx(t).dy(e)}}),b.extend(b.Rect,b.Ellipse,b.Circle,b.Gradient,b.FX,{radius:function(t,e){var i=(this._target||this).type;return"radial"==i||"circle"==i?this.attr("r",new b.Number(t)):this.rx(t).ry(null==e?t:e)}}),b.extend(b.Path,{length:function(){return this.node.getTotalLength()},pointAt:function(t){return this.node.getPointAtLength(t)}}),b.extend(b.Parent,b.Text,b.Tspan,b.FX,{font:function(t,e){if("object"==typeof t)for(e in t)this.font(e,t[e]);return"leading"==t?this.leading(e):"anchor"==t?this.attr("text-anchor",e):"size"==t||"family"==t||"weight"==t||"stretch"==t||"variant"==t||"style"==t?this.attr("font-"+t,e):this.attr(t,e)}}),b.Set=b.invent({create:function(t){t instanceof b.Set?this.members=t.members.slice():Array.isArray(t)?this.members=t:this.clear()},extend:{add:function(){var t,e,i=[].slice.call(arguments);for(t=0,e=i.length;t-1&&this.members.splice(e,1),this},each:function(t){for(var e=0,i=this.members.length;e=0},index:function(t){return this.members.indexOf(t)},get:function(t){return this.members[t]},first:function(){return this.get(0)},last:function(){return this.get(this.members.length-1)},valueOf:function(){return this.members},bbox:function(){if(0==this.members.length)return new b.RBox;var t=this.members[0].rbox(this.members[0].doc());return this.each(function(){t=t.merge(this.rbox(this.doc()))}),t}},construct:{set:function(t){ +return new b.Set(t)}}}),b.FX.Set=b.invent({create:function(t){this.set=t}}),b.Set.inherit=function(){var t,e=[];for(var t in b.Shape.prototype)"function"==typeof b.Shape.prototype[t]&&"function"!=typeof b.Set.prototype[t]&&e.push(t);e.forEach(function(t){b.Set.prototype[t]=function(){for(var e=0,i=this.members.length;e=0;t--)delete this.memory()[arguments[t]];return this},memory:function(){return this._memory||(this._memory={})}}),b.get=function(t){var i=e.getElementById(v(t)||t);return b.adopt(i)},b.select=function(t,i){return new b.Set(b.utils.map((i||e).querySelectorAll(t),function(t){return b.adopt(t)}))},b.extend(b.Parent,{select:function(t){return b.select(t,this.node)}});var k="abcdef".split("");if("function"!=typeof t.CustomEvent){var S=function(t,i){i=i||{bubbles:!1,cancelable:!1,detail:void 0};var n=e.createEvent("CustomEvent");return n.initCustomEvent(t,i.bubbles,i.cancelable,i.detail),n};S.prototype=t.Event.prototype,b.CustomEvent=S}else b.CustomEvent=t.CustomEvent;return function(e){for(var i=0,n=["moz","webkit"],r=0;r= this.resizeLimits.width) { + if (checkAspectRatio) { + snap = this.checkAspectRatio(snap, checkAspectRatioReverse); + } + + if (this.parameters.type === "text") { + if (resizeFont) { + this.el.move(this.parameters.box.x + snap[0], this.parameters.box.y); + this.el.attr("font-size", this.parameters.fontSize - snap[0]); + } + return; + } + + this.el.width(this.parameters.box.width - snap[0]); + + if (updateOnlyChanges) { + this.el.x(this.parameters.box.x + snap[0]); + } else { + this.el.move(this.parameters.box.x + snap[0], this.parameters.box.y); + } + } + }; + + this._resizeRight = function (snap, resizeFont, checkAspectRatio, checkAspectRatioReverse) { + if (this.parameters.box.width + snap[0] >= this.resizeLimits.width) { + if (checkAspectRatio) { + snap = this.checkAspectRatio(snap, checkAspectRatioReverse); + } + + if (this.parameters.type === "text") { + if (resizeFont) { + this.el.move(this.parameters.box.x - snap[0], this.parameters.box.y); + this.el.attr("font-size", this.parameters.fontSize + snap[0]); + } + return; + } + + this.el.x(this.parameters.box.x).width(this.parameters.box.width + snap[0]); + } + }; + + this._resizeTop = function (snap, checkAspectRatio, checkAspectRatioReverse, updateOnlyChanges) { + if (this.parameters.box.height - snap[1] >= this.resizeLimits.height) { + if (checkAspectRatio) { + snap = this.checkAspectRatio(snap, checkAspectRatioReverse); + } + + // Disable the font-resizing if it is not from the corner of bounding-box + if (this.parameters.type === "text") { + return; + } + + this.el.height(this.parameters.box.height - snap[1]); + + if (updateOnlyChanges) { + this.el.y(this.parameters.box.y + snap[1]) + } else { + this.el.move(this.parameters.box.x, this.parameters.box.y + snap[1]); + } + } + }; + + this._resizeBottom = function (snap, checkAspectRatio, checkAspectRatioReverse) { + if (this.parameters.box.height + snap[1] >= this.resizeLimits.height) { + if (checkAspectRatio) { + snap = this.checkAspectRatio(snap, checkAspectRatioReverse); + } + + if (this.parameters.type === "text") { + return; + } + + this.el.y(this.parameters.box.y).height(this.parameters.box.height + snap[1]); + } + }; + + // Lets check which edge of the bounding-box was clicked and resize the this.el according to this + switch (event.type) { + + // Left-Top-Edge + case 'lt': + // We build a calculating function for every case which gives us the new position of the this.el + this.calc = function (diffX, diffY) { + // The procedure is always the same + // First we snap the edge to the given grid (snapping to 1px grid is normal resizing) + var snap = this.snapToGrid(diffX, diffY); + + this._resizeTop(snap, true, false, true); + this._resizeLeft(snap, true, true, false, true); + }; + break; + + // Right-Top + case 'rt': + // s.a. + this.calc = function (diffX, diffY) { + var snap = this.snapToGrid(diffX, diffY, 1 << 1); + + this._resizeTop(snap, true, true, true); + this._resizeRight(snap, true, true, true); + }; + break; + + // Right-Bottom + case 'rb': + // s.a. + this.calc = function (diffX, diffY) { + var snap = this.snapToGrid(diffX, diffY, 0); + + this._resizeBottom(snap, true); + this._resizeRight(snap, true, true); + }; + break; + + // Left-Bottom + case 'lb': + // s.a. + this.calc = function (diffX, diffY) { + var snap = this.snapToGrid(diffX, diffY, 1); + + this._resizeBottom(snap, true, true); + this._resizeLeft(snap, true, true, true, true); + }; + break; + + // Top + case 't': + // s.a. + this.calc = function (diffX, diffY) { + var snap = this.snapToGrid(diffX, diffY, 1 << 1); + + this._resizeTop(snap); + }; + break; + + // Right + case 'r': + // s.a. + this.calc = function (diffX, diffY) { + var snap = this.snapToGrid(diffX, diffY, 0); + + this._resizeRight(snap); + }; + break; + + // Bottom + case 'b': + // s.a. + this.calc = function (diffX, diffY) { + var snap = this.snapToGrid(diffX, diffY, 0); + + this._resizeBottom(snap); + }; + break; + + // Left + case 'l': + // s.a. + this.calc = function (diffX, diffY) { + var snap = this.snapToGrid(diffX, diffY, 1); + + this._resizeLeft(snap); + }; + break; + + // Rotation + case 'rot': + // s.a. + this.calc = function (diffX, diffY) { + + // yes this is kinda stupid but we need the mouse coords back... + var current = {x: diffX + this.parameters.p.x, y: diffY + this.parameters.p.y}; + + // start minus middle + var sAngle = Math.atan2((this.parameters.p.y - this.parameters.box.y - this.parameters.box.height / 2), (this.parameters.p.x - this.parameters.box.x - this.parameters.box.width / 2)); + + // end minus middle + var pAngle = Math.atan2((current.y - this.parameters.box.y - this.parameters.box.height / 2), (current.x - this.parameters.box.x - this.parameters.box.width / 2)); + + var angle = this.parameters.rotation + (pAngle - sAngle) * 180 / Math.PI + this.options.snapToAngle / 2; + + // We have to move the element to the center of the box first and change the rotation afterwards + // because rotation always works around a rotation-center, which is changed when moving the element + // We also set the new rotation center to the center of the box. + this.el.center(this.parameters.box.cx, this.parameters.box.cy).rotate(angle - (angle % this.options.snapToAngle), this.parameters.box.cx, this.parameters.box.cy); + }; + break; + + // Moving one single Point (needed when an element is deepSelected which means you can move every single point of the object) + case 'point': + this.calc = function (diffX, diffY) { + + // Snapping the point to the grid + var snap = this.snapToGrid(diffX, diffY, this.parameters.pointCoords[0], this.parameters.pointCoords[1]); + + // Get the point array + var array = this.el.array().valueOf(); + + // Changing the moved point in the array + array[this.parameters.i][0] = this.parameters.pointCoords[0] + snap[0]; + array[this.parameters.i][1] = this.parameters.pointCoords[1] + snap[1]; + + // And plot the new this.el + this.el.plot(array); + }; + } + + this.el.fire('resizestart', {dx: this.parameters.x, dy: this.parameters.y, event: event}); + // When resizing started, we have to register events for... + // Touches. + SVG.on(window, 'touchmove.resize', function(e) { + _this.update(e || window.event); + }); + SVG.on(window, 'touchend.resize', function() { + _this.done(); + }); + // Mouse. + SVG.on(window, 'mousemove.resize', function (e) { + _this.update(e || window.event); + }); + SVG.on(window, 'mouseup.resize', function () { + _this.done(); + }); + + }; + + // The update-function redraws the element every time the mouse is moving + ResizeHandler.prototype.update = function (event) { + + if (!event) { + if (this.lastUpdateCall) { + this.calc(this.lastUpdateCall[0], this.lastUpdateCall[1]); + } + return; + } + + // Calculate the difference between the mouseposition at start and now + var txPt = this._extractPosition(event); + var p = this.transformPoint(txPt.x, txPt.y); + + var diffX = p.x - this.parameters.p.x, + diffY = p.y - this.parameters.p.y; + + this.lastUpdateCall = [diffX, diffY]; + + // Calculate the new position and height / width of the element + this.calc(diffX, diffY); + + // Emit an event to say we have changed. + this.el.fire('resizing', {dx: diffX, dy: diffY, event: event}); + }; + + // Is called on mouseup. + // Removes the update-function from the mousemove event + ResizeHandler.prototype.done = function () { + this.lastUpdateCall = null; + SVG.off(window, 'mousemove.resize'); + SVG.off(window, 'mouseup.resize'); + SVG.off(window, 'touchmove.resize'); + SVG.off(window, 'touchend.resize'); + this.el.fire('resizedone'); + }; + + // The flag is used to determine whether the resizing is used with a left-Point (first bit) and top-point (second bit) + // In this cases the temp-values are calculated differently + ResizeHandler.prototype.snapToGrid = function (diffX, diffY, flag, pointCoordsY) { + + var temp; + + // If `pointCoordsY` is given, a single Point has to be snapped (deepSelect). That's why we need a different temp-value + if (typeof pointCoordsY !== 'undefined') { + // Note that flag = pointCoordsX in this case + temp = [(flag + diffX) % this.options.snapToGrid, (pointCoordsY + diffY) % this.options.snapToGrid]; + } else { + // We check if the flag is set and if not we set a default-value (both bits set - which means upper-left-edge) + flag = flag == null ? 1 | 1 << 1 : flag; + temp = [(this.parameters.box.x + diffX + (flag & 1 ? 0 : this.parameters.box.width)) % this.options.snapToGrid, (this.parameters.box.y + diffY + (flag & (1 << 1) ? 0 : this.parameters.box.height)) % this.options.snapToGrid]; + } + + if(diffX < 0) { + temp[0] -= this.options.snapToGrid; + } + if(diffY < 0) { + temp[1] -= this.options.snapToGrid; + } + + diffX -= (Math.abs(temp[0]) < this.options.snapToGrid / 2 ? + temp[0] : + temp[0] - (diffX < 0 ? -this.options.snapToGrid : this.options.snapToGrid)); + diffY -= (Math.abs(temp[1]) < this.options.snapToGrid / 2 ? + temp[1] : + temp[1] - (diffY < 0 ? -this.options.snapToGrid : this.options.snapToGrid)); + + return this.constraintToBox(diffX, diffY, flag, pointCoordsY); + + }; + + // keep element within constrained box + ResizeHandler.prototype.constraintToBox = function (diffX, diffY, flag, pointCoordsY) { + //return [diffX, diffY] + var c = this.options.constraint || {}; + var orgX, orgY; + + if (typeof pointCoordsY !== 'undefined') { + orgX = flag; + orgY = pointCoordsY; + } else { + orgX = this.parameters.box.x + (flag & 1 ? 0 : this.parameters.box.width); + orgY = this.parameters.box.y + (flag & (1<<1) ? 0 : this.parameters.box.height); + } + + if (typeof c.minX !== 'undefined' && orgX + diffX < c.minX) { + diffX = c.minX - orgX; + } + + if (typeof c.maxX !== 'undefined' && orgX + diffX > c.maxX) { + diffX = c.maxX - orgX; + } + + if (typeof c.minY !== 'undefined' && orgY + diffY < c.minY) { + diffY = c.minY - orgY; + } + + if (typeof c.maxY !== 'undefined' && orgY + diffY > c.maxY) { + diffY = c.maxY - orgY; + } + + return [diffX, diffY]; + }; + + ResizeHandler.prototype.checkAspectRatio = function (snap, isReverse) { + if (!this.options.saveAspectRatio) { + return snap; + } + + var updatedSnap = snap.slice(); + var aspectRatio = this.parameters.box.width / this.parameters.box.height; + var newW = this.parameters.box.width + snap[0]; + var newH = this.parameters.box.height - snap[1]; + var newAspectRatio = newW / newH; + + if (newAspectRatio < aspectRatio) { + // Height is too big. Adapt it + updatedSnap[1] = newW / aspectRatio - this.parameters.box.height; + isReverse && (updatedSnap[1] = -updatedSnap[1]); + } else if (newAspectRatio > aspectRatio) { + // Width is too big. Adapt it + updatedSnap[0] = this.parameters.box.width - newH * aspectRatio; + isReverse && (updatedSnap[0] = -updatedSnap[0]); + } + + return updatedSnap; + }; + + SVG.extend(SVG.Element, { + // Resize element with mouse + resize: function (options) { + + (this.remember('_resizeHandler') || new ResizeHandler(this)).init(options || {}); + + return this; + + } + + }); + + SVG.Element.prototype.resize.defaults = { + snapToAngle: 0.1, // Specifies the speed the rotation is happening when moving the mouse + snapToGrid: 1, // Snaps to a grid of `snapToGrid` Pixels + constraint: {}, // keep element within constrained box + resizeLimits: { width: 0, height: 0 }, // rect limit size on resize + saveAspectRatio: false // Save aspect ratio when resizing using lt, rt, rb or lb points + }; + +}).call(this); +}()); diff --git a/hal-core/resources/web/js/lib/svg.resize.min.js b/hal-core/resources/web/js/lib/svg.resize.min.js new file mode 100644 index 00000000..aef5e88a --- /dev/null +++ b/hal-core/resources/web/js/lib/svg.resize.min.js @@ -0,0 +1 @@ +/*! svg.resize.js v1.4.3 MIT*/;!function(){"use strict";(function(){function t(t){t.remember("_resizeHandler",this),this.el=t,this.parameters={},this.lastUpdateCall=null,this.p=t.doc().node.createSVGPoint()}t.prototype.transformPoint=function(t,e,i){return this.p.x=t-(this.offset.x-window.pageXOffset),this.p.y=e-(this.offset.y-window.pageYOffset),this.p.matrixTransform(i||this.m)},t.prototype._extractPosition=function(t){return{x:null!=t.clientX?t.clientX:t.touches[0].clientX,y:null!=t.clientY?t.clientY:t.touches[0].clientY}},t.prototype.init=function(t){var e=this;if(this.stop(),"stop"!==t){this.options={};for(var i in this.el.resize.defaults)this.options[i]=this.el.resize.defaults[i],void 0!==t[i]&&(this.options[i]=t[i]);this.el.on("lt.resize",function(t){e.resize(t||window.event)}),this.el.on("rt.resize",function(t){e.resize(t||window.event)}),this.el.on("rb.resize",function(t){e.resize(t||window.event)}),this.el.on("lb.resize",function(t){e.resize(t||window.event)}),this.el.on("t.resize",function(t){e.resize(t||window.event)}),this.el.on("r.resize",function(t){e.resize(t||window.event)}),this.el.on("b.resize",function(t){e.resize(t||window.event)}),this.el.on("l.resize",function(t){e.resize(t||window.event)}),this.el.on("rot.resize",function(t){e.resize(t||window.event)}),this.el.on("point.resize",function(t){e.resize(t||window.event)}),this.update()}},t.prototype.stop=function(){return this.el.off("lt.resize"),this.el.off("rt.resize"),this.el.off("rb.resize"),this.el.off("lb.resize"),this.el.off("t.resize"),this.el.off("r.resize"),this.el.off("b.resize"),this.el.off("l.resize"),this.el.off("rot.resize"),this.el.off("point.resize"),this},t.prototype.resize=function(t){var e=this;this.m=this.el.node.getScreenCTM().inverse(),this.offset={x:window.pageXOffset,y:window.pageYOffset};var i=this._extractPosition(t.detail.event);if(this.parameters={type:this.el.type,p:this.transformPoint(i.x,i.y),x:t.detail.x,y:t.detail.y,box:this.el.bbox(),rotation:this.el.transform().rotation},this.resizeLimits=this.options.resizeLimits||this.resize.defaults.resizeLimits,"text"===this.el.type&&(this.parameters.fontSize=this.el.attr()["font-size"]),void 0!==t.detail.i){var s=this.el.array().valueOf();this.parameters.i=t.detail.i,this.parameters.pointCoords=[s[t.detail.i][0],s[t.detail.i][1]]}switch(this._resizeLeft=function(t,e,i,s,r){if(this.parameters.box.width-t[0]>=this.resizeLimits.width){if(i&&(t=this.checkAspectRatio(t,s)),"text"===this.parameters.type)return void(e&&(this.el.move(this.parameters.box.x+t[0],this.parameters.box.y),this.el.attr("font-size",this.parameters.fontSize-t[0])));this.el.width(this.parameters.box.width-t[0]),r?this.el.x(this.parameters.box.x+t[0]):this.el.move(this.parameters.box.x+t[0],this.parameters.box.y)}},this._resizeRight=function(t,e,i,s){if(this.parameters.box.width+t[0]>=this.resizeLimits.width){if(i&&(t=this.checkAspectRatio(t,s)),"text"===this.parameters.type)return void(e&&(this.el.move(this.parameters.box.x-t[0],this.parameters.box.y),this.el.attr("font-size",this.parameters.fontSize+t[0])));this.el.x(this.parameters.box.x).width(this.parameters.box.width+t[0])}},this._resizeTop=function(t,e,i,s){if(this.parameters.box.height-t[1]>=this.resizeLimits.height){if(e&&(t=this.checkAspectRatio(t,i)),"text"===this.parameters.type)return;this.el.height(this.parameters.box.height-t[1]),s?this.el.y(this.parameters.box.y+t[1]):this.el.move(this.parameters.box.x,this.parameters.box.y+t[1])}},this._resizeBottom=function(t,e,i){if(this.parameters.box.height+t[1]>=this.resizeLimits.height){if(e&&(t=this.checkAspectRatio(t,i)),"text"===this.parameters.type)return;this.el.y(this.parameters.box.y).height(this.parameters.box.height+t[1])}},t.type){case"lt":this.calc=function(t,e){var i=this.snapToGrid(t,e);this._resizeTop(i,!0,!1,!0),this._resizeLeft(i,!0,!0,!1,!0)};break;case"rt":this.calc=function(t,e){var i=this.snapToGrid(t,e,2);this._resizeTop(i,!0,!0,!0),this._resizeRight(i,!0,!0,!0)};break;case"rb":this.calc=function(t,e){var i=this.snapToGrid(t,e,0);this._resizeBottom(i,!0),this._resizeRight(i,!0,!0)};break;case"lb":this.calc=function(t,e){var i=this.snapToGrid(t,e,1);this._resizeBottom(i,!0,!0),this._resizeLeft(i,!0,!0,!0,!0)};break;case"t":this.calc=function(t,e){var i=this.snapToGrid(t,e,2);this._resizeTop(i)};break;case"r":this.calc=function(t,e){var i=this.snapToGrid(t,e,0);this._resizeRight(i)};break;case"b":this.calc=function(t,e){var i=this.snapToGrid(t,e,0);this._resizeBottom(i)};break;case"l":this.calc=function(t,e){var i=this.snapToGrid(t,e,1);this._resizeLeft(i)};break;case"rot":this.calc=function(t,e){var i={x:t+this.parameters.p.x,y:e+this.parameters.p.y},s=Math.atan2(this.parameters.p.y-this.parameters.box.y-this.parameters.box.height/2,this.parameters.p.x-this.parameters.box.x-this.parameters.box.width/2),r=Math.atan2(i.y-this.parameters.box.y-this.parameters.box.height/2,i.x-this.parameters.box.x-this.parameters.box.width/2),o=this.parameters.rotation+180*(r-s)/Math.PI+this.options.snapToAngle/2;this.el.center(this.parameters.box.cx,this.parameters.box.cy).rotate(o-o%this.options.snapToAngle,this.parameters.box.cx,this.parameters.box.cy)};break;case"point":this.calc=function(t,e){var i=this.snapToGrid(t,e,this.parameters.pointCoords[0],this.parameters.pointCoords[1]),s=this.el.array().valueOf();s[this.parameters.i][0]=this.parameters.pointCoords[0]+i[0],s[this.parameters.i][1]=this.parameters.pointCoords[1]+i[1],this.el.plot(s)}}this.el.fire("resizestart",{dx:this.parameters.x,dy:this.parameters.y,event:t}),SVG.on(window,"touchmove.resize",function(t){e.update(t||window.event)}),SVG.on(window,"touchend.resize",function(){e.done()}),SVG.on(window,"mousemove.resize",function(t){e.update(t||window.event)}),SVG.on(window,"mouseup.resize",function(){e.done()})},t.prototype.update=function(t){if(!t)return void(this.lastUpdateCall&&this.calc(this.lastUpdateCall[0],this.lastUpdateCall[1]));var e=this._extractPosition(t),i=this.transformPoint(e.x,e.y),s=i.x-this.parameters.p.x,r=i.y-this.parameters.p.y;this.lastUpdateCall=[s,r],this.calc(s,r),this.el.fire("resizing",{dx:s,dy:r,event:t})},t.prototype.done=function(){this.lastUpdateCall=null,SVG.off(window,"mousemove.resize"),SVG.off(window,"mouseup.resize"),SVG.off(window,"touchmove.resize"),SVG.off(window,"touchend.resize"),this.el.fire("resizedone")},t.prototype.snapToGrid=function(t,e,i,s){var r;return void 0!==s?r=[(i+t)%this.options.snapToGrid,(s+e)%this.options.snapToGrid]:(i=null==i?3:i,r=[(this.parameters.box.x+t+(1&i?0:this.parameters.box.width))%this.options.snapToGrid,(this.parameters.box.y+e+(2&i?0:this.parameters.box.height))%this.options.snapToGrid]),t<0&&(r[0]-=this.options.snapToGrid),e<0&&(r[1]-=this.options.snapToGrid),t-=Math.abs(r[0])a.maxX&&(t=a.maxX-r),void 0!==a.minY&&o+ea.maxY&&(e=a.maxY-o),[t,e]},t.prototype.checkAspectRatio=function(t,e){if(!this.options.saveAspectRatio)return t;var i=t.slice(),s=this.parameters.box.width/this.parameters.box.height,r=this.parameters.box.width+t[0],o=this.parameters.box.height-t[1],a=r/o;return as&&(i[0]=this.parameters.box.width-o*s,e&&(i[0]=-i[0])),i},SVG.extend(SVG.Element,{resize:function(e){return(this.remember("_resizeHandler")||new t(this)).init(e||{}),this}}),SVG.Element.prototype.resize.defaults={snapToAngle:.1,snapToGrid:1,constraint:{},resizeLimits:{width:0,height:0},saveAspectRatio:!1}}).call(this)}(); \ No newline at end of file diff --git a/hal-core/resources/web/js/lib/svg.select.LICENSE.txt b/hal-core/resources/web/js/lib/svg.select.LICENSE.txt new file mode 100644 index 00000000..ca43f864 --- /dev/null +++ b/hal-core/resources/web/js/lib/svg.select.LICENSE.txt @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2014 Fuzzy + +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. \ No newline at end of file diff --git a/hal-core/resources/web/js/lib/svg.select.js b/hal-core/resources/web/js/lib/svg.select.js new file mode 100644 index 00000000..cfd8acb5 --- /dev/null +++ b/hal-core/resources/web/js/lib/svg.select.js @@ -0,0 +1,425 @@ +/*! +* svg.select.js - An extension of svg.js which allows to select elements with mouse +* @version 3.0.1 +* https://github.com/svgdotjs/svg.select.js +* +* @copyright Ulrich-Matthias Schäfer +* @license MIT +*/; +;(function() { +"use strict"; + +function SelectHandler(el) { + + this.el = el; + el.remember('_selectHandler', this); + this.pointSelection = {isSelected: false}; + this.rectSelection = {isSelected: false}; + + // helper list with position settings of each type of point + this.pointsList = { + lt: [ 0, 0 ], + rt: [ 'width', 0 ], + rb: [ 'width', 'height' ], + lb: [ 0, 'height' ], + t: [ 'width', 0 ], + r: [ 'width', 'height' ], + b: [ 'width', 'height' ], + l: [ 0, 'height' ] + }; + + // helper function to get point coordinates based on settings above and an object (bbox in our case) + this.pointCoord = function (setting, object, isPointCentered) { + var coord = typeof setting !== 'string' ? setting : object[setting]; + // Top, bottom, right and left points are placed in the center of element width/height + return isPointCentered ? coord / 2 : coord + } + + this.pointCoords = function (point, object) { + var settings = this.pointsList[point]; + + return { + x: this.pointCoord(settings[0], object, (point === 't' || point === 'b')), + y: this.pointCoord(settings[1], object, (point === 'r' || point === 'l')) + } + } +} + +SelectHandler.prototype.init = function (value, options) { + + var bbox = this.el.bbox(); + this.options = {}; + + // store defaults list of points in order to verify users config + var points = this.el.selectize.defaults.points; + + // Merging the defaults and the options-object together + for (var i in this.el.selectize.defaults) { + this.options[i] = this.el.selectize.defaults[i]; + if (options[i] !== undefined) { + this.options[i] = options[i]; + } + } + + // prepare & validate list of points to be added (or excluded) + var pointsLists = ['points', 'pointsExclude']; + + for (var i in pointsLists) { + var option = this.options[pointsLists[i]]; + + if (typeof option === 'string') { + if (option.length > 0) { + // if set as comma separated string list => convert it into an array + option = option.split(/\s*,\s*/i); + } else { + option = []; + } + } else if (typeof option === 'boolean' && pointsLists[i] === 'points') { + // this is not needed, but let's have it for legacy support + option = option ? points : []; + } + + this.options[pointsLists[i]] = option; + } + + // intersect correct all points options with users config (exclude unwanted points) + // ES5 -> NO arrow functions nor Array.includes() + this.options.points = [ points, this.options.points ].reduce( + function (a, b) { + return a.filter( + function (c) { + return b.indexOf(c) > -1; + } + ) + } + ); + + // exclude pointsExclude, if wanted + this.options.points = [ this.options.points, this.options.pointsExclude ].reduce( + function (a, b) { + return a.filter( + function (c) { + return b.indexOf(c) < 0; + } + ) + } + ); + + this.parent = this.el.parent(); + this.nested = (this.nested || this.parent.group()); + this.nested.matrix(new SVG.Matrix(this.el).translate(bbox.x, bbox.y)); + + // When deepSelect is enabled and the element is a line/polyline/polygon, draw only points for moving + if (this.options.deepSelect && ['line', 'polyline', 'polygon'].indexOf(this.el.type) !== -1) { + this.selectPoints(value); + } else { + this.selectRect(value); + } + + this.observe(); + this.cleanup(); + +}; + +SelectHandler.prototype.selectPoints = function (value) { + + this.pointSelection.isSelected = value; + + // When set is already there we dont have to create one + if (this.pointSelection.set) { + return this; + } + + // Create our set of elements + this.pointSelection.set = this.parent.set(); + // draw the points and mark the element as selected + this.drawPoints(); + + return this; + +}; + +// create the point-array which contains the 2 points of a line or simply the points-array of polyline/polygon +SelectHandler.prototype.getPointArray = function () { + var bbox = this.el.bbox(); + + return this.el.array().valueOf().map(function (el) { + return [el[0] - bbox.x, el[1] - bbox.y]; + }); +}; + +// Draws a points +SelectHandler.prototype.drawPoints = function () { + + var _this = this, array = this.getPointArray(); + + // go through the array of points + for (var i = 0, len = array.length; i < len; ++i) { + + var curriedEvent = (function (k) { + return function (ev) { + ev = ev || window.event; + ev.preventDefault ? ev.preventDefault() : ev.returnValue = false; + ev.stopPropagation(); + + var x = ev.pageX || ev.touches[0].pageX; + var y = ev.pageY || ev.touches[0].pageY; + _this.el.fire('point', {x: x, y: y, i: k, event: ev}); + }; + })(i); + + // add every point to the set + // add css-classes and a touchstart-event which fires our event for moving points + var point = this.drawPoint(array[i][0], array[i][1]) + .addClass(this.options.classPoints) + .addClass(this.options.classPoints + '_point') + .on('touchstart', curriedEvent) + .on('mousedown', curriedEvent) + this.pointSelection.set.add(point); + } +}; + +// The function to draw single point +SelectHandler.prototype.drawPoint = function (cx, cy) { + var pointType = this.options.pointType; + + switch (pointType) { + case 'circle': + return this.drawCircle(cx, cy); + case 'rect': + return this.drawRect(cx, cy); + default: + if (typeof pointType === 'function') { + return pointType.call(this, cx, cy); + } + + throw new Error('Unknown ' + pointType + ' point type!'); + } +}; + +// The function to draw the circle point +SelectHandler.prototype.drawCircle = function (cx, cy) { + return this.nested.circle(this.options.pointSize) + .stroke(this.options.pointStroke) + .fill(this.options.pointFill) + .center(cx, cy); +}; + +// The function to draw the rect point +SelectHandler.prototype.drawRect = function (cx, cy) { + return this.nested.rect(this.options.pointSize, this.options.pointSize) + .stroke(this.options.pointStroke) + .fill(this.options.pointFill) + .center(cx, cy); +}; + +// every time a point is moved, we have to update the positions of our point +SelectHandler.prototype.updatePointSelection = function () { + var array = this.getPointArray(); + + this.pointSelection.set.each(function (i) { + if (this.cx() === array[i][0] && this.cy() === array[i][1]) { + return; + } + this.center(array[i][0], array[i][1]); + }); +}; + +SelectHandler.prototype.updateRectSelection = function () { + var _this = this, bbox = this.el.bbox(); + + this.rectSelection.set.get(0).attr({ + width: bbox.width, + height: bbox.height + }); + + // set.get(1) is always in the upper left corner. no need to move it + if (this.options.points.length) { + this.options.points.map(function (point, index) { + var coords = _this.pointCoords(point, bbox); + + _this.rectSelection.set.get(index + 1).center(coords.x, coords.y); + }); + } + + if (this.options.rotationPoint) { + var length = this.rectSelection.set.length(); + + this.rectSelection.set.get(length - 1).center(bbox.width / 2, 20); + } +}; + +SelectHandler.prototype.selectRect = function (value) { + + var _this = this, bbox = this.el.bbox(); + + this.rectSelection.isSelected = value; + + // when set is already p + this.rectSelection.set = this.rectSelection.set || this.parent.set(); + + // helperFunction to create a mouse-down function which triggers the event specified in `eventName` + function getMoseDownFunc(eventName) { + return function (ev) { + ev = ev || window.event; + ev.preventDefault ? ev.preventDefault() : ev.returnValue = false; + ev.stopPropagation(); + + var x = ev.pageX || ev.touches[0].pageX; + var y = ev.pageY || ev.touches[0].pageY; + _this.el.fire(eventName, {x: x, y: y, event: ev}); + }; + } + + // create the selection-rectangle and add the css-class + if (!this.rectSelection.set.get(0)) { + this.rectSelection.set.add(this.nested.rect(bbox.width, bbox.height).addClass(this.options.classRect)); + } + + // Draw Points at the edges, if enabled + if (this.options.points.length && this.rectSelection.set.length() < 2) { + var ename ="touchstart", mname = "mousedown"; + + this.options.points.map(function (point, index) { + var coords = _this.pointCoords(point, bbox); + + var pointElement = _this.drawPoint(coords.x, coords.y) + .attr('class', _this.options.classPoints + '_' + point) + .on(mname, getMoseDownFunc(point)) + .on(ename, getMoseDownFunc(point)); + _this.rectSelection.set.add(pointElement); + }); + + this.rectSelection.set.each(function () { + this.addClass(_this.options.classPoints); + }); + } + + // draw rotationPint, if enabled + if (this.options.rotationPoint && ((this.options.points && !this.rectSelection.set.get(9)) || (!this.options.points && !this.rectSelection.set.get(1)))) { + + var curriedEvent = function (ev) { + ev = ev || window.event; + ev.preventDefault ? ev.preventDefault() : ev.returnValue = false; + ev.stopPropagation(); + + var x = ev.pageX || ev.touches[0].pageX; + var y = ev.pageY || ev.touches[0].pageY; + _this.el.fire('rot', {x: x, y: y, event: ev}); + }; + + var pointElement = this.drawPoint(bbox.width / 2, 20) + .attr('class', this.options.classPoints + '_rot') + .on("touchstart", curriedEvent) + .on("mousedown", curriedEvent); + this.rectSelection.set.add(pointElement); + } + +}; + +SelectHandler.prototype.handler = function () { + + var bbox = this.el.bbox(); + this.nested.matrix(new SVG.Matrix(this.el).translate(bbox.x, bbox.y)); + + if (this.rectSelection.isSelected) { + this.updateRectSelection(); + } + + if (this.pointSelection.isSelected) { + this.updatePointSelection(); + } + +}; + +SelectHandler.prototype.observe = function () { + var _this = this; + + if (MutationObserver) { + if (this.rectSelection.isSelected || this.pointSelection.isSelected) { + this.observerInst = this.observerInst || new MutationObserver(function () { + _this.handler(); + }); + this.observerInst.observe(this.el.node, {attributes: true}); + } else { + try { + this.observerInst.disconnect(); + delete this.observerInst; + } catch (e) { + } + } + } else { + this.el.off('DOMAttrModified.select'); + + if (this.rectSelection.isSelected || this.pointSelection.isSelected) { + this.el.on('DOMAttrModified.select', function () { + _this.handler(); + }); + } + } +}; + +SelectHandler.prototype.cleanup = function () { + + //var _this = this; + + if (!this.rectSelection.isSelected && this.rectSelection.set) { + // stop watching the element, remove the selection + this.rectSelection.set.each(function () { + this.remove(); + }); + + this.rectSelection.set.clear(); + delete this.rectSelection.set; + } + + if (!this.pointSelection.isSelected && this.pointSelection.set) { + // Remove all points, clear the set, stop watching the element + this.pointSelection.set.each(function () { + this.remove(); + }); + + this.pointSelection.set.clear(); + delete this.pointSelection.set; + } + + if (!this.pointSelection.isSelected && !this.rectSelection.isSelected) { + this.nested.remove(); + delete this.nested; + + } +}; + + +SVG.extend(SVG.Element, { + // Select element with mouse + selectize: function (value, options) { + + // Check the parameters and reassign if needed + if (typeof value === 'object') { + options = value; + value = true; + } + + var selectHandler = this.remember('_selectHandler') || new SelectHandler(this); + + selectHandler.init(value === undefined ? true : value, options || {}); + + return this; + + } +}); + +SVG.Element.prototype.selectize.defaults = { + points: ['lt', 'rt', 'rb', 'lb', 't', 'r', 'b', 'l'], // which points to draw, default all + pointsExclude: [], // easier option if to exclude few than rewrite all + classRect: 'svg_select_boundingRect', // Css-class added to the rect + classPoints: 'svg_select_points', // Css-class added to the points + pointSize: 7, // size of point + rotationPoint: true, // If true, rotation point is drawn. Needed for rotation! + deepSelect: false, // If true, moving of single points is possible (only line, polyline, polyon) + pointType: 'circle', // Point type: circle or rect, default circle + pointFill: "#000", // Point fill color + pointStroke: { width: 1, color: "#000" } // Point stroke properties +}; +}()); \ No newline at end of file diff --git a/hal-core/resources/web/js/lib/svg.select.min.js b/hal-core/resources/web/js/lib/svg.select.min.js new file mode 100644 index 00000000..56e232fb --- /dev/null +++ b/hal-core/resources/web/js/lib/svg.select.min.js @@ -0,0 +1 @@ +/*! svg.select.js v3.0.1 MIT*/;!function(){"use strict";function i(t){(this.el=t).remember("_selectHandler",this),this.pointSelection={isSelected:!1},this.rectSelection={isSelected:!1},this.pointsList={lt:[0,0],rt:["width",0],rb:["width","height"],lb:[0,"height"],t:["width",0],r:["width","height"],b:["width","height"],l:[0,"height"]},this.pointCoord=function(t,e,i){var o="string"!=typeof t?t:e[t];return i?o/2:o},this.pointCoords=function(t,e){var i=this.pointsList[t];return{x:this.pointCoord(i[0],e,"t"===t||"b"===t),y:this.pointCoord(i[1],e,"r"===t||"l"===t)}}}i.prototype.init=function(t,e){var i=this.el.bbox();this.options={};var o=this.el.selectize.defaults.points;for(var s in this.el.selectize.defaults)this.options[s]=this.el.selectize.defaults[s],void 0!==e[s]&&(this.options[s]=e[s]);var n=["points","pointsExclude"];for(var s in n){var r=this.options[n[s]];"string"==typeof r?r=0 + + + {{message}}   + +
+ ` +} \ No newline at end of file diff --git a/hal-core/resources/web/js/vue/components/AlertListComponent.js b/hal-core/resources/web/js/vue/components/AlertListComponent.js new file mode 100644 index 00000000..d82edba4 --- /dev/null +++ b/hal-core/resources/web/js/vue/components/AlertListComponent.js @@ -0,0 +1,29 @@ +import Alert from 'AlertComponent' +import { alertStore } from 'AlertStore' + +export default { + data() { + return { + alertStore + } + }, + components: { + Alert, + }, + mounted() { + alertStore.enableAutoLoad(true); + }, + template: ` + + +
+ +
` +} \ No newline at end of file diff --git a/hal-core/resources/web/js/vue/components/App.js b/hal-core/resources/web/js/vue/components/App.js new file mode 100644 index 00000000..6a2131c6 --- /dev/null +++ b/hal-core/resources/web/js/vue/components/App.js @@ -0,0 +1,17 @@ +import AlertList from 'AlertListComponent' + +export default { + data() { + return { + } + }, + components: { + AlertList, + }, + template: ` +
+ + + +
` +} \ No newline at end of file diff --git a/hal-core/resources/web/js/vue/components/EventActionComponent.js b/hal-core/resources/web/js/vue/components/EventActionComponent.js new file mode 100644 index 00000000..43bf215f --- /dev/null +++ b/hal-core/resources/web/js/vue/components/EventActionComponent.js @@ -0,0 +1,49 @@ +import {eventStore} from 'EventStore' +import { alertStore } from 'AlertStore' + +export default { + props: { + 'id': {default: 0}, + }, + data() { + let internalEvent = eventStore.getEvent(this.id); + return { + event: internalEvent, + checkboxChecked: internalEvent.data?.valueStr == 'ON', + } + }, + methods: { + changeState(changeEvent) { + fetch('/api/event?' + new URLSearchParams({ + id: this.event.id, + action: "modify", + data: changeEvent.target.type == "checkbox" ? this.checkboxChecked : changeEvent.target.value + }).toString(), { + method: 'PUT', + headers: { + 'Accept': 'application/json', + }, + }) + .then(response => response.json()) + .then(json => { + if (json['error'] != null) { + alertStore.alertError(json['error']); + return; + } + }) + } + }, + template: ` +
+ + + +
+ ` +} \ No newline at end of file diff --git a/hal-core/resources/web/js/vue/components/EventDetailPageComponent.js b/hal-core/resources/web/js/vue/components/EventDetailPageComponent.js new file mode 100644 index 00000000..4d1a5446 --- /dev/null +++ b/hal-core/resources/web/js/vue/components/EventDetailPageComponent.js @@ -0,0 +1,88 @@ +import {eventStore} from 'EventStore' + +export default { + data() { + var id = this.$route.params.id; + return { + id: id, + event: eventStore.getEvent(id), + } + }, + template: ` +

Details for {{event.name}}

+ +
+
+
Configuration
+
+
TimestampDataRaw Data
+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
Event ID:{{event.id}
Name:{{event.name}}
Type:{{event.configType}}
Owner:{{event.owner}}

State: +
+ + + +
+ +
+
+
{{name}}:{{confValue}}
+ + + + +
+
+
History data
+
+ + + + + + + + + + +
TimestampRaw Data
{{event.data.timestamp}}{{event.data.value}}
+
+
+
+ + + ` +} \ No newline at end of file diff --git a/hal-core/resources/web/js/vue/components/EventOverviewPageComponent.js b/hal-core/resources/web/js/vue/components/EventOverviewPageComponent.js new file mode 100644 index 00000000..2a05b6ca --- /dev/null +++ b/hal-core/resources/web/js/vue/components/EventOverviewPageComponent.js @@ -0,0 +1,21 @@ +import EventTable from 'EventTableComponent' + +export default { + props: { + }, + components: { + EventTable, + }, + template: ` +

Event Overview

+ +
+
+
Local Events
+
+ +
+
+
+ ` +} \ No newline at end of file diff --git a/hal-core/resources/web/js/vue/components/EventTableComponent.js b/hal-core/resources/web/js/vue/components/EventTableComponent.js new file mode 100644 index 00000000..18f62de9 --- /dev/null +++ b/hal-core/resources/web/js/vue/components/EventTableComponent.js @@ -0,0 +1,34 @@ +import {eventStore} from 'EventStore' +import EventTableRow from 'EventTableRowComponent' + +export default { + data() { + return { + eventStore, + } + }, + components: { + EventTableRow, + }, + mounted() { + eventStore.enableAutoLoad(true); + }, + unmounted() { + eventStore.enableAutoLoad(false); + }, + template: ` + + + + + + + + + + + + +
NameTypeDataLast UpdateActions
+ ` +} \ No newline at end of file diff --git a/hal-core/resources/web/js/vue/components/EventTableRowComponent.js b/hal-core/resources/web/js/vue/components/EventTableRowComponent.js new file mode 100644 index 00000000..0d7afc24 --- /dev/null +++ b/hal-core/resources/web/js/vue/components/EventTableRowComponent.js @@ -0,0 +1,29 @@ +import {eventStore} from 'EventStore' +import EventAction from 'EventActionComponent' + +export default { + props: { + 'id': {default: 0}, + }, + data() { + let event = eventStore.getEvent(this.id) + return { + event: event, + timestamp: getRelTimestamp(event.data?.timestamp) + } + }, + components: { + EventAction + }, + template: ` + + {{ event.name }} + {{ event.configType }} + {{ event.data?.valueStr }} + {{ timestamp }} + + + + + ` +} \ No newline at end of file diff --git a/hal-core/resources/web/js/vue/stores/AlertStore.js b/hal-core/resources/web/js/vue/stores/AlertStore.js new file mode 100644 index 00000000..9bd2abde --- /dev/null +++ b/hal-core/resources/web/js/vue/stores/AlertStore.js @@ -0,0 +1,46 @@ +import { reactive } from 'vue' + +export const alertStore = reactive({ + loading: false, + alerts: [], + pollTimer: null, + + enableAutoLoad(enabled = true) { + if (enabled && this.pollTimer !== null) { + this.pollTimer = setInterval(function() { + load(); + }, 3000); + } else { + clearInterval(this.timer); + this.pollTimer == null; + } + }, + + load() { + fetch('/api/alert?action=poll') + .then(response => response.json()) + .then(data => { + data.forEach(alert => { + alert.source = "server"; + alertStore.alerts.push(alert); + }); + }); + }, + + setLoading(l = true) { + this.loading = l; + }, + + addAlertInfo(message) { + this.alerts.push({source: "local", level: "info", message: message}); + }, + addAlertSuccess(message) { + this.alerts.push({source: "local", level: "success", message: message}); + }, + addAlertWarning(message) { + this.alerts.push({source: "local", level: "warning", message: message}); + }, + AddAlertError(message) { + this.alerts.push({source: "local", level: "danger", message: message}); + }, +}); \ No newline at end of file diff --git a/hal-core/resources/web/js/vue/stores/EventStore.js b/hal-core/resources/web/js/vue/stores/EventStore.js new file mode 100644 index 00000000..93efe359 --- /dev/null +++ b/hal-core/resources/web/js/vue/stores/EventStore.js @@ -0,0 +1,49 @@ +import { reactive } from 'vue' +import { alertStore } from 'AlertStore' + +export const eventStore = reactive({ + events: [], + pollTimerId: null, + pollInterval: 10000, // 10 sec + + enableAutoLoad(enabled = true) { + if (enabled) { + if (this.pollTimerId !== null) + return; // Timer already initialized + eventStore.load(); + + this.pollTimerId = setInterval(function() { + eventStore.load(); + }, this.pollInterval); + } else { + clearInterval(this.pollTimerId); + this.pollTimerId == null; + } + }, + + load() { + alertStore.setLoading(true); + + fetch('/api/event', { + method: 'GET', + headers: { + 'Accept': 'application/json', + }, + }) + .then(response => response.json()) + .then(json => { + if (json['error'] != null) { + alertStore.alertError(json['error']); + return; + } + + eventStore.events = json; + alertStore.setLoading(false); + }) + }, + + getEvent(id) { + let event = eventStore.events.find(event => id == event.id); + return event; + } +}); \ No newline at end of file diff --git a/hal-core/resources/web/js/vue/stores/SensorStore.js b/hal-core/resources/web/js/vue/stores/SensorStore.js new file mode 100644 index 00000000..d57e91ff --- /dev/null +++ b/hal-core/resources/web/js/vue/stores/SensorStore.js @@ -0,0 +1,44 @@ +import { reactive } from 'vue' +import { alertStore } from 'AlertStore' + +export const sensorStore = reactive({ + sensors: {}, + pollTimerId: null, + pollInterval: 10000, // 10 sec + + enableAutoLoad(enabled = true) { + if (enabled) { + if (this.pollTimerId !== null) + return; // Timer already initialized + sensorStore.load(); + + this.pollTimerId = setInterval(function() { + sensorStore.load(); + }, this.pollInterval); + } else { + clearInterval(this.pollTimerId); + this.pollTimerId == null; + } + }, + + load() { + alertStore.setLoading(true); + + fetch('/api/sensor', { + method: 'GET', + headers: { + 'Accept': 'application/json', + }, + }) + .then(response => response.json()) + .then(json => { + if (json['error'] != null) { + alertStore.alertError(json['error']); + return; + } + + sensorStore.sensors = json; + alertStore.setLoading(false); + }) + }, +}); \ No newline at end of file diff --git a/hal-core/resources/web/js/vue/vue-router.esm-browser.js b/hal-core/resources/web/js/vue/vue-router.esm-browser.js new file mode 100644 index 00000000..64c8126c --- /dev/null +++ b/hal-core/resources/web/js/vue/vue-router.esm-browser.js @@ -0,0 +1,3615 @@ +/*! + * vue-router v4.2.5 + * (c) 2023 Eduardo San Martin Morote + * @license MIT + */ +import { getCurrentInstance, inject, onUnmounted, onDeactivated, onActivated, computed, unref, watchEffect, defineComponent, reactive, h, provide, ref, watch, shallowRef, shallowReactive, nextTick } from 'vue'; +import { setupDevtoolsPlugin } from '@vue/devtools-api'; + +const isBrowser = typeof window !== 'undefined'; + +function isESModule(obj) { + return obj.__esModule || obj[Symbol.toStringTag] === 'Module'; +} +const assign = Object.assign; +function applyToParams(fn, params) { + const newParams = {}; + for (const key in params) { + const value = params[key]; + newParams[key] = isArray(value) + ? value.map(fn) + : fn(value); + } + return newParams; +} +const noop = () => { }; +/** + * Typesafe alternative to Array.isArray + * https://github.com/microsoft/TypeScript/pull/48228 + */ +const isArray = Array.isArray; + +function warn(msg) { + // avoid using ...args as it breaks in older Edge builds + const args = Array.from(arguments).slice(1); + console.warn.apply(console, ['[Vue Router warn]: ' + msg].concat(args)); +} + +const TRAILING_SLASH_RE = /\/$/; +const removeTrailingSlash = (path) => path.replace(TRAILING_SLASH_RE, ''); +/** + * Transforms a URI into a normalized history location + * + * @param parseQuery + * @param location - URI to normalize + * @param currentLocation - current absolute location. Allows resolving relative + * paths. Must start with `/`. Defaults to `/` + * @returns a normalized history location + */ +function parseURL(parseQuery, location, currentLocation = '/') { + let path, query = {}, searchString = '', hash = ''; + // Could use URL and URLSearchParams but IE 11 doesn't support it + // TODO: move to new URL() + const hashPos = location.indexOf('#'); + let searchPos = location.indexOf('?'); + // the hash appears before the search, so it's not part of the search string + if (hashPos < searchPos && hashPos >= 0) { + searchPos = -1; + } + if (searchPos > -1) { + path = location.slice(0, searchPos); + searchString = location.slice(searchPos + 1, hashPos > -1 ? hashPos : location.length); + query = parseQuery(searchString); + } + if (hashPos > -1) { + path = path || location.slice(0, hashPos); + // keep the # character + hash = location.slice(hashPos, location.length); + } + // no search and no query + path = resolveRelativePath(path != null ? path : location, currentLocation); + // empty path means a relative query or hash `?foo=f`, `#thing` + return { + fullPath: path + (searchString && '?') + searchString + hash, + path, + query, + hash, + }; +} +/** + * Stringifies a URL object + * + * @param stringifyQuery + * @param location + */ +function stringifyURL(stringifyQuery, location) { + const query = location.query ? stringifyQuery(location.query) : ''; + return location.path + (query && '?') + query + (location.hash || ''); +} +/** + * Strips off the base from the beginning of a location.pathname in a non-case-sensitive way. + * + * @param pathname - location.pathname + * @param base - base to strip off + */ +function stripBase(pathname, base) { + // no base or base is not found at the beginning + if (!base || !pathname.toLowerCase().startsWith(base.toLowerCase())) + return pathname; + return pathname.slice(base.length) || '/'; +} +/** + * Checks if two RouteLocation are equal. This means that both locations are + * pointing towards the same {@link RouteRecord} and that all `params`, `query` + * parameters and `hash` are the same + * + * @param stringifyQuery - A function that takes a query object of type LocationQueryRaw and returns a string representation of it. + * @param a - first {@link RouteLocation} + * @param b - second {@link RouteLocation} + */ +function isSameRouteLocation(stringifyQuery, a, b) { + const aLastIndex = a.matched.length - 1; + const bLastIndex = b.matched.length - 1; + return (aLastIndex > -1 && + aLastIndex === bLastIndex && + isSameRouteRecord(a.matched[aLastIndex], b.matched[bLastIndex]) && + isSameRouteLocationParams(a.params, b.params) && + stringifyQuery(a.query) === stringifyQuery(b.query) && + a.hash === b.hash); +} +/** + * Check if two `RouteRecords` are equal. Takes into account aliases: they are + * considered equal to the `RouteRecord` they are aliasing. + * + * @param a - first {@link RouteRecord} + * @param b - second {@link RouteRecord} + */ +function isSameRouteRecord(a, b) { + // since the original record has an undefined value for aliasOf + // but all aliases point to the original record, this will always compare + // the original record + return (a.aliasOf || a) === (b.aliasOf || b); +} +function isSameRouteLocationParams(a, b) { + if (Object.keys(a).length !== Object.keys(b).length) + return false; + for (const key in a) { + if (!isSameRouteLocationParamsValue(a[key], b[key])) + return false; + } + return true; +} +function isSameRouteLocationParamsValue(a, b) { + return isArray(a) + ? isEquivalentArray(a, b) + : isArray(b) + ? isEquivalentArray(b, a) + : a === b; +} +/** + * Check if two arrays are the same or if an array with one single entry is the + * same as another primitive value. Used to check query and parameters + * + * @param a - array of values + * @param b - array of values or a single value + */ +function isEquivalentArray(a, b) { + return isArray(b) + ? a.length === b.length && a.every((value, i) => value === b[i]) + : a.length === 1 && a[0] === b; +} +/** + * Resolves a relative path that starts with `.`. + * + * @param to - path location we are resolving + * @param from - currentLocation.path, should start with `/` + */ +function resolveRelativePath(to, from) { + if (to.startsWith('/')) + return to; + if (!from.startsWith('/')) { + warn(`Cannot resolve a relative location without an absolute path. Trying to resolve "${to}" from "${from}". It should look like "/${from}".`); + return to; + } + if (!to) + return from; + const fromSegments = from.split('/'); + const toSegments = to.split('/'); + const lastToSegment = toSegments[toSegments.length - 1]; + // make . and ./ the same (../ === .., ../../ === ../..) + // this is the same behavior as new URL() + if (lastToSegment === '..' || lastToSegment === '.') { + toSegments.push(''); + } + let position = fromSegments.length - 1; + let toPosition; + let segment; + for (toPosition = 0; toPosition < toSegments.length; toPosition++) { + segment = toSegments[toPosition]; + // we stay on the same position + if (segment === '.') + continue; + // go up in the from array + if (segment === '..') { + // we can't go below zero, but we still need to increment toPosition + if (position > 1) + position--; + // continue + } + // we reached a non-relative path, we stop here + else + break; + } + return (fromSegments.slice(0, position).join('/') + + '/' + + toSegments + // ensure we use at least the last element in the toSegments + .slice(toPosition - (toPosition === toSegments.length ? 1 : 0)) + .join('/')); +} + +var NavigationType; +(function (NavigationType) { + NavigationType["pop"] = "pop"; + NavigationType["push"] = "push"; +})(NavigationType || (NavigationType = {})); +var NavigationDirection; +(function (NavigationDirection) { + NavigationDirection["back"] = "back"; + NavigationDirection["forward"] = "forward"; + NavigationDirection["unknown"] = ""; +})(NavigationDirection || (NavigationDirection = {})); +/** + * Starting location for Histories + */ +const START = ''; +// Generic utils +/** + * Normalizes a base by removing any trailing slash and reading the base tag if + * present. + * + * @param base - base to normalize + */ +function normalizeBase(base) { + if (!base) { + if (isBrowser) { + // respect tag + const baseEl = document.querySelector('base'); + base = (baseEl && baseEl.getAttribute('href')) || '/'; + // strip full URL origin + base = base.replace(/^\w+:\/\/[^\/]+/, ''); + } + else { + base = '/'; + } + } + // ensure leading slash when it was removed by the regex above avoid leading + // slash with hash because the file could be read from the disk like file:// + // and the leading slash would cause problems + if (base[0] !== '/' && base[0] !== '#') + base = '/' + base; + // remove the trailing slash so all other method can just do `base + fullPath` + // to build an href + return removeTrailingSlash(base); +} +// remove any character before the hash +const BEFORE_HASH_RE = /^[^#]+#/; +function createHref(base, location) { + return base.replace(BEFORE_HASH_RE, '#') + location; +} + +function getElementPosition(el, offset) { + const docRect = document.documentElement.getBoundingClientRect(); + const elRect = el.getBoundingClientRect(); + return { + behavior: offset.behavior, + left: elRect.left - docRect.left - (offset.left || 0), + top: elRect.top - docRect.top - (offset.top || 0), + }; +} +const computeScrollPosition = () => ({ + left: window.pageXOffset, + top: window.pageYOffset, +}); +function scrollToPosition(position) { + let scrollToOptions; + if ('el' in position) { + const positionEl = position.el; + const isIdSelector = typeof positionEl === 'string' && positionEl.startsWith('#'); + /** + * `id`s can accept pretty much any characters, including CSS combinators + * like `>` or `~`. It's still possible to retrieve elements using + * `document.getElementById('~')` but it needs to be escaped when using + * `document.querySelector('#\\~')` for it to be valid. The only + * requirements for `id`s are them to be unique on the page and to not be + * empty (`id=""`). Because of that, when passing an id selector, it should + * be properly escaped for it to work with `querySelector`. We could check + * for the id selector to be simple (no CSS combinators `+ >~`) but that + * would make things inconsistent since they are valid characters for an + * `id` but would need to be escaped when using `querySelector`, breaking + * their usage and ending up in no selector returned. Selectors need to be + * escaped: + * + * - `#1-thing` becomes `#\31 -thing` + * - `#with~symbols` becomes `#with\\~symbols` + * + * - More information about the topic can be found at + * https://mathiasbynens.be/notes/html5-id-class. + * - Practical example: https://mathiasbynens.be/demo/html5-id + */ + if (typeof position.el === 'string') { + if (!isIdSelector || !document.getElementById(position.el.slice(1))) { + try { + const foundEl = document.querySelector(position.el); + if (isIdSelector && foundEl) { + warn(`The selector "${position.el}" should be passed as "el: document.querySelector('${position.el}')" because it starts with "#".`); + // return to avoid other warnings + return; + } + } + catch (err) { + warn(`The selector "${position.el}" is invalid. If you are using an id selector, make sure to escape it. You can find more information about escaping characters in selectors at https://mathiasbynens.be/notes/css-escapes or use CSS.escape (https://developer.mozilla.org/en-US/docs/Web/API/CSS/escape).`); + // return to avoid other warnings + return; + } + } + } + const el = typeof positionEl === 'string' + ? isIdSelector + ? document.getElementById(positionEl.slice(1)) + : document.querySelector(positionEl) + : positionEl; + if (!el) { + warn(`Couldn't find element using selector "${position.el}" returned by scrollBehavior.`); + return; + } + scrollToOptions = getElementPosition(el, position); + } + else { + scrollToOptions = position; + } + if ('scrollBehavior' in document.documentElement.style) + window.scrollTo(scrollToOptions); + else { + window.scrollTo(scrollToOptions.left != null ? scrollToOptions.left : window.pageXOffset, scrollToOptions.top != null ? scrollToOptions.top : window.pageYOffset); + } +} +function getScrollKey(path, delta) { + const position = history.state ? history.state.position - delta : -1; + return position + path; +} +const scrollPositions = new Map(); +function saveScrollPosition(key, scrollPosition) { + scrollPositions.set(key, scrollPosition); +} +function getSavedScrollPosition(key) { + const scroll = scrollPositions.get(key); + // consume it so it's not used again + scrollPositions.delete(key); + return scroll; +} +// TODO: RFC about how to save scroll position +/** + * ScrollBehavior instance used by the router to compute and restore the scroll + * position when navigating. + */ +// export interface ScrollHandler { +// // returns a scroll position that can be saved in history +// compute(): ScrollPositionEntry +// // can take an extended ScrollPositionEntry +// scroll(position: ScrollPosition): void +// } +// export const scrollHandler: ScrollHandler = { +// compute: computeScroll, +// scroll: scrollToPosition, +// } + +let createBaseLocation = () => location.protocol + '//' + location.host; +/** + * Creates a normalized history location from a window.location object + * @param base - The base path + * @param location - The window.location object + */ +function createCurrentLocation(base, location) { + const { pathname, search, hash } = location; + // allows hash bases like #, /#, #/, #!, #!/, /#!/, or even /folder#end + const hashPos = base.indexOf('#'); + if (hashPos > -1) { + let slicePos = hash.includes(base.slice(hashPos)) + ? base.slice(hashPos).length + : 1; + let pathFromHash = hash.slice(slicePos); + // prepend the starting slash to hash so the url starts with /# + if (pathFromHash[0] !== '/') + pathFromHash = '/' + pathFromHash; + return stripBase(pathFromHash, ''); + } + const path = stripBase(pathname, base); + return path + search + hash; +} +function useHistoryListeners(base, historyState, currentLocation, replace) { + let listeners = []; + let teardowns = []; + // TODO: should it be a stack? a Dict. Check if the popstate listener + // can trigger twice + let pauseState = null; + const popStateHandler = ({ state, }) => { + const to = createCurrentLocation(base, location); + const from = currentLocation.value; + const fromState = historyState.value; + let delta = 0; + if (state) { + currentLocation.value = to; + historyState.value = state; + // ignore the popstate and reset the pauseState + if (pauseState && pauseState === from) { + pauseState = null; + return; + } + delta = fromState ? state.position - fromState.position : 0; + } + else { + replace(to); + } + // Here we could also revert the navigation by calling history.go(-delta) + // this listener will have to be adapted to not trigger again and to wait for the url + // to be updated before triggering the listeners. Some kind of validation function would also + // need to be passed to the listeners so the navigation can be accepted + // call all listeners + listeners.forEach(listener => { + listener(currentLocation.value, from, { + delta, + type: NavigationType.pop, + direction: delta + ? delta > 0 + ? NavigationDirection.forward + : NavigationDirection.back + : NavigationDirection.unknown, + }); + }); + }; + function pauseListeners() { + pauseState = currentLocation.value; + } + function listen(callback) { + // set up the listener and prepare teardown callbacks + listeners.push(callback); + const teardown = () => { + const index = listeners.indexOf(callback); + if (index > -1) + listeners.splice(index, 1); + }; + teardowns.push(teardown); + return teardown; + } + function beforeUnloadListener() { + const { history } = window; + if (!history.state) + return; + history.replaceState(assign({}, history.state, { scroll: computeScrollPosition() }), ''); + } + function destroy() { + for (const teardown of teardowns) + teardown(); + teardowns = []; + window.removeEventListener('popstate', popStateHandler); + window.removeEventListener('beforeunload', beforeUnloadListener); + } + // set up the listeners and prepare teardown callbacks + window.addEventListener('popstate', popStateHandler); + // TODO: could we use 'pagehide' or 'visibilitychange' instead? + // https://developer.chrome.com/blog/page-lifecycle-api/ + window.addEventListener('beforeunload', beforeUnloadListener, { + passive: true, + }); + return { + pauseListeners, + listen, + destroy, + }; +} +/** + * Creates a state object + */ +function buildState(back, current, forward, replaced = false, computeScroll = false) { + return { + back, + current, + forward, + replaced, + position: window.history.length, + scroll: computeScroll ? computeScrollPosition() : null, + }; +} +function useHistoryStateNavigation(base) { + const { history, location } = window; + // private variables + const currentLocation = { + value: createCurrentLocation(base, location), + }; + const historyState = { value: history.state }; + // build current history entry as this is a fresh navigation + if (!historyState.value) { + changeLocation(currentLocation.value, { + back: null, + current: currentLocation.value, + forward: null, + // the length is off by one, we need to decrease it + position: history.length - 1, + replaced: true, + // don't add a scroll as the user may have an anchor, and we want + // scrollBehavior to be triggered without a saved position + scroll: null, + }, true); + } + function changeLocation(to, state, replace) { + /** + * if a base tag is provided, and we are on a normal domain, we have to + * respect the provided `base` attribute because pushState() will use it and + * potentially erase anything before the `#` like at + * https://github.com/vuejs/router/issues/685 where a base of + * `/folder/#` but a base of `/` would erase the `/folder/` section. If + * there is no host, the `` tag makes no sense and if there isn't a + * base tag we can just use everything after the `#`. + */ + const hashIndex = base.indexOf('#'); + const url = hashIndex > -1 + ? (location.host && document.querySelector('base') + ? base + : base.slice(hashIndex)) + to + : createBaseLocation() + base + to; + try { + // BROWSER QUIRK + // NOTE: Safari throws a SecurityError when calling this function 100 times in 30 seconds + history[replace ? 'replaceState' : 'pushState'](state, '', url); + historyState.value = state; + } + catch (err) { + { + warn('Error with push/replace State', err); + } + // Force the navigation, this also resets the call count + location[replace ? 'replace' : 'assign'](url); + } + } + function replace(to, data) { + const state = assign({}, history.state, buildState(historyState.value.back, + // keep back and forward entries but override current position + to, historyState.value.forward, true), data, { position: historyState.value.position }); + changeLocation(to, state, true); + currentLocation.value = to; + } + function push(to, data) { + // Add to current entry the information of where we are going + // as well as saving the current position + const currentState = assign({}, + // use current history state to gracefully handle a wrong call to + // history.replaceState + // https://github.com/vuejs/router/issues/366 + historyState.value, history.state, { + forward: to, + scroll: computeScrollPosition(), + }); + if (!history.state) { + warn(`history.state seems to have been manually replaced without preserving the necessary values. Make sure to preserve existing history state if you are manually calling history.replaceState:\n\n` + + `history.replaceState(history.state, '', url)\n\n` + + `You can find more information at https://next.router.vuejs.org/guide/migration/#usage-of-history-state.`); + } + changeLocation(currentState.current, currentState, true); + const state = assign({}, buildState(currentLocation.value, to, null), { position: currentState.position + 1 }, data); + changeLocation(to, state, false); + currentLocation.value = to; + } + return { + location: currentLocation, + state: historyState, + push, + replace, + }; +} +/** + * Creates an HTML5 history. Most common history for single page applications. + * + * @param base - + */ +function createWebHistory(base) { + base = normalizeBase(base); + const historyNavigation = useHistoryStateNavigation(base); + const historyListeners = useHistoryListeners(base, historyNavigation.state, historyNavigation.location, historyNavigation.replace); + function go(delta, triggerListeners = true) { + if (!triggerListeners) + historyListeners.pauseListeners(); + history.go(delta); + } + const routerHistory = assign({ + // it's overridden right after + location: '', + base, + go, + createHref: createHref.bind(null, base), + }, historyNavigation, historyListeners); + Object.defineProperty(routerHistory, 'location', { + enumerable: true, + get: () => historyNavigation.location.value, + }); + Object.defineProperty(routerHistory, 'state', { + enumerable: true, + get: () => historyNavigation.state.value, + }); + return routerHistory; +} + +/** + * Creates an in-memory based history. The main purpose of this history is to handle SSR. It starts in a special location that is nowhere. + * It's up to the user to replace that location with the starter location by either calling `router.push` or `router.replace`. + * + * @param base - Base applied to all urls, defaults to '/' + * @returns a history object that can be passed to the router constructor + */ +function createMemoryHistory(base = '') { + let listeners = []; + let queue = [START]; + let position = 0; + base = normalizeBase(base); + function setLocation(location) { + position++; + if (position !== queue.length) { + // we are in the middle, we remove everything from here in the queue + queue.splice(position); + } + queue.push(location); + } + function triggerListeners(to, from, { direction, delta }) { + const info = { + direction, + delta, + type: NavigationType.pop, + }; + for (const callback of listeners) { + callback(to, from, info); + } + } + const routerHistory = { + // rewritten by Object.defineProperty + location: START, + // TODO: should be kept in queue + state: {}, + base, + createHref: createHref.bind(null, base), + replace(to) { + // remove current entry and decrement position + queue.splice(position--, 1); + setLocation(to); + }, + push(to, data) { + setLocation(to); + }, + listen(callback) { + listeners.push(callback); + return () => { + const index = listeners.indexOf(callback); + if (index > -1) + listeners.splice(index, 1); + }; + }, + destroy() { + listeners = []; + queue = [START]; + position = 0; + }, + go(delta, shouldTrigger = true) { + const from = this.location; + const direction = + // we are considering delta === 0 going forward, but in abstract mode + // using 0 for the delta doesn't make sense like it does in html5 where + // it reloads the page + delta < 0 ? NavigationDirection.back : NavigationDirection.forward; + position = Math.max(0, Math.min(position + delta, queue.length - 1)); + if (shouldTrigger) { + triggerListeners(this.location, from, { + direction, + delta, + }); + } + }, + }; + Object.defineProperty(routerHistory, 'location', { + enumerable: true, + get: () => queue[position], + }); + return routerHistory; +} + +/** + * Creates a hash history. Useful for web applications with no host (e.g. `file://`) or when configuring a server to + * handle any URL is not possible. + * + * @param base - optional base to provide. Defaults to `location.pathname + location.search` If there is a `` tag + * in the `head`, its value will be ignored in favor of this parameter **but note it affects all the history.pushState() + * calls**, meaning that if you use a `` tag, it's `href` value **has to match this parameter** (ignoring anything + * after the `#`). + * + * @example + * ```js + * // at https://example.com/folder + * createWebHashHistory() // gives a url of `https://example.com/folder#` + * createWebHashHistory('/folder/') // gives a url of `https://example.com/folder/#` + * // if the `#` is provided in the base, it won't be added by `createWebHashHistory` + * createWebHashHistory('/folder/#/app/') // gives a url of `https://example.com/folder/#/app/` + * // you should avoid doing this because it changes the original url and breaks copying urls + * createWebHashHistory('/other-folder/') // gives a url of `https://example.com/other-folder/#` + * + * // at file:///usr/etc/folder/index.html + * // for locations with no `host`, the base is ignored + * createWebHashHistory('/iAmIgnored') // gives a url of `file:///usr/etc/folder/index.html#` + * ``` + */ +function createWebHashHistory(base) { + // Make sure this implementation is fine in terms of encoding, specially for IE11 + // for `file://`, directly use the pathname and ignore the base + // location.pathname contains an initial `/` even at the root: `https://example.com` + base = location.host ? base || location.pathname + location.search : ''; + // allow the user to provide a `#` in the middle: `/base/#/app` + if (!base.includes('#')) + base += '#'; + if (!base.endsWith('#/') && !base.endsWith('#')) { + warn(`A hash base must end with a "#":\n"${base}" should be "${base.replace(/#.*$/, '#')}".`); + } + return createWebHistory(base); +} + +function isRouteLocation(route) { + return typeof route === 'string' || (route && typeof route === 'object'); +} +function isRouteName(name) { + return typeof name === 'string' || typeof name === 'symbol'; +} + +/** + * Initial route location where the router is. Can be used in navigation guards + * to differentiate the initial navigation. + * + * @example + * ```js + * import { START_LOCATION } from 'vue-router' + * + * router.beforeEach((to, from) => { + * if (from === START_LOCATION) { + * // initial navigation + * } + * }) + * ``` + */ +const START_LOCATION_NORMALIZED = { + path: '/', + name: undefined, + params: {}, + query: {}, + hash: '', + fullPath: '/', + matched: [], + meta: {}, + redirectedFrom: undefined, +}; + +const NavigationFailureSymbol = Symbol('navigation failure' ); +/** + * Enumeration with all possible types for navigation failures. Can be passed to + * {@link isNavigationFailure} to check for specific failures. + */ +var NavigationFailureType; +(function (NavigationFailureType) { + /** + * An aborted navigation is a navigation that failed because a navigation + * guard returned `false` or called `next(false)` + */ + NavigationFailureType[NavigationFailureType["aborted"] = 4] = "aborted"; + /** + * A cancelled navigation is a navigation that failed because a more recent + * navigation finished started (not necessarily finished). + */ + NavigationFailureType[NavigationFailureType["cancelled"] = 8] = "cancelled"; + /** + * A duplicated navigation is a navigation that failed because it was + * initiated while already being at the exact same location. + */ + NavigationFailureType[NavigationFailureType["duplicated"] = 16] = "duplicated"; +})(NavigationFailureType || (NavigationFailureType = {})); +// DEV only debug messages +const ErrorTypeMessages = { + [1 /* ErrorTypes.MATCHER_NOT_FOUND */]({ location, currentLocation }) { + return `No match for\n ${JSON.stringify(location)}${currentLocation + ? '\nwhile being at\n' + JSON.stringify(currentLocation) + : ''}`; + }, + [2 /* ErrorTypes.NAVIGATION_GUARD_REDIRECT */]({ from, to, }) { + return `Redirected from "${from.fullPath}" to "${stringifyRoute(to)}" via a navigation guard.`; + }, + [4 /* ErrorTypes.NAVIGATION_ABORTED */]({ from, to }) { + return `Navigation aborted from "${from.fullPath}" to "${to.fullPath}" via a navigation guard.`; + }, + [8 /* ErrorTypes.NAVIGATION_CANCELLED */]({ from, to }) { + return `Navigation cancelled from "${from.fullPath}" to "${to.fullPath}" with a new navigation.`; + }, + [16 /* ErrorTypes.NAVIGATION_DUPLICATED */]({ from, to }) { + return `Avoided redundant navigation to current location: "${from.fullPath}".`; + }, +}; +function createRouterError(type, params) { + // keep full error messages in cjs versions + { + return assign(new Error(ErrorTypeMessages[type](params)), { + type, + [NavigationFailureSymbol]: true, + }, params); + } +} +function isNavigationFailure(error, type) { + return (error instanceof Error && + NavigationFailureSymbol in error && + (type == null || !!(error.type & type))); +} +const propertiesToLog = ['params', 'query', 'hash']; +function stringifyRoute(to) { + if (typeof to === 'string') + return to; + if ('path' in to) + return to.path; + const location = {}; + for (const key of propertiesToLog) { + if (key in to) + location[key] = to[key]; + } + return JSON.stringify(location, null, 2); +} + +// default pattern for a param: non-greedy everything but / +const BASE_PARAM_PATTERN = '[^/]+?'; +const BASE_PATH_PARSER_OPTIONS = { + sensitive: false, + strict: false, + start: true, + end: true, +}; +// Special Regex characters that must be escaped in static tokens +const REGEX_CHARS_RE = /[.+*?^${}()[\]/\\]/g; +/** + * Creates a path parser from an array of Segments (a segment is an array of Tokens) + * + * @param segments - array of segments returned by tokenizePath + * @param extraOptions - optional options for the regexp + * @returns a PathParser + */ +function tokensToParser(segments, extraOptions) { + const options = assign({}, BASE_PATH_PARSER_OPTIONS, extraOptions); + // the amount of scores is the same as the length of segments except for the root segment "/" + const score = []; + // the regexp as a string + let pattern = options.start ? '^' : ''; + // extracted keys + const keys = []; + for (const segment of segments) { + // the root segment needs special treatment + const segmentScores = segment.length ? [] : [90 /* PathScore.Root */]; + // allow trailing slash + if (options.strict && !segment.length) + pattern += '/'; + for (let tokenIndex = 0; tokenIndex < segment.length; tokenIndex++) { + const token = segment[tokenIndex]; + // resets the score if we are inside a sub-segment /:a-other-:b + let subSegmentScore = 40 /* PathScore.Segment */ + + (options.sensitive ? 0.25 /* PathScore.BonusCaseSensitive */ : 0); + if (token.type === 0 /* TokenType.Static */) { + // prepend the slash if we are starting a new segment + if (!tokenIndex) + pattern += '/'; + pattern += token.value.replace(REGEX_CHARS_RE, '\\$&'); + subSegmentScore += 40 /* PathScore.Static */; + } + else if (token.type === 1 /* TokenType.Param */) { + const { value, repeatable, optional, regexp } = token; + keys.push({ + name: value, + repeatable, + optional, + }); + const re = regexp ? regexp : BASE_PARAM_PATTERN; + // the user provided a custom regexp /:id(\\d+) + if (re !== BASE_PARAM_PATTERN) { + subSegmentScore += 10 /* PathScore.BonusCustomRegExp */; + // make sure the regexp is valid before using it + try { + new RegExp(`(${re})`); + } + catch (err) { + throw new Error(`Invalid custom RegExp for param "${value}" (${re}): ` + + err.message); + } + } + // when we repeat we must take care of the repeating leading slash + let subPattern = repeatable ? `((?:${re})(?:/(?:${re}))*)` : `(${re})`; + // prepend the slash if we are starting a new segment + if (!tokenIndex) + subPattern = + // avoid an optional / if there are more segments e.g. /:p?-static + // or /:p?-:p2 + optional && segment.length < 2 + ? `(?:/${subPattern})` + : '/' + subPattern; + if (optional) + subPattern += '?'; + pattern += subPattern; + subSegmentScore += 20 /* PathScore.Dynamic */; + if (optional) + subSegmentScore += -8 /* PathScore.BonusOptional */; + if (repeatable) + subSegmentScore += -20 /* PathScore.BonusRepeatable */; + if (re === '.*') + subSegmentScore += -50 /* PathScore.BonusWildcard */; + } + segmentScores.push(subSegmentScore); + } + // an empty array like /home/ -> [[{home}], []] + // if (!segment.length) pattern += '/' + score.push(segmentScores); + } + // only apply the strict bonus to the last score + if (options.strict && options.end) { + const i = score.length - 1; + score[i][score[i].length - 1] += 0.7000000000000001 /* PathScore.BonusStrict */; + } + // TODO: dev only warn double trailing slash + if (!options.strict) + pattern += '/?'; + if (options.end) + pattern += '$'; + // allow paths like /dynamic to only match dynamic or dynamic/... but not dynamic_something_else + else if (options.strict) + pattern += '(?:/|$)'; + const re = new RegExp(pattern, options.sensitive ? '' : 'i'); + function parse(path) { + const match = path.match(re); + const params = {}; + if (!match) + return null; + for (let i = 1; i < match.length; i++) { + const value = match[i] || ''; + const key = keys[i - 1]; + params[key.name] = value && key.repeatable ? value.split('/') : value; + } + return params; + } + function stringify(params) { + let path = ''; + // for optional parameters to allow to be empty + let avoidDuplicatedSlash = false; + for (const segment of segments) { + if (!avoidDuplicatedSlash || !path.endsWith('/')) + path += '/'; + avoidDuplicatedSlash = false; + for (const token of segment) { + if (token.type === 0 /* TokenType.Static */) { + path += token.value; + } + else if (token.type === 1 /* TokenType.Param */) { + const { value, repeatable, optional } = token; + const param = value in params ? params[value] : ''; + if (isArray(param) && !repeatable) { + throw new Error(`Provided param "${value}" is an array but it is not repeatable (* or + modifiers)`); + } + const text = isArray(param) + ? param.join('/') + : param; + if (!text) { + if (optional) { + // if we have more than one optional param like /:a?-static we don't need to care about the optional param + if (segment.length < 2) { + // remove the last slash as we could be at the end + if (path.endsWith('/')) + path = path.slice(0, -1); + // do not append a slash on the next iteration + else + avoidDuplicatedSlash = true; + } + } + else + throw new Error(`Missing required param "${value}"`); + } + path += text; + } + } + } + // avoid empty path when we have multiple optional params + return path || '/'; + } + return { + re, + score, + keys, + parse, + stringify, + }; +} +/** + * Compares an array of numbers as used in PathParser.score and returns a + * number. This function can be used to `sort` an array + * + * @param a - first array of numbers + * @param b - second array of numbers + * @returns 0 if both are equal, < 0 if a should be sorted first, > 0 if b + * should be sorted first + */ +function compareScoreArray(a, b) { + let i = 0; + while (i < a.length && i < b.length) { + const diff = b[i] - a[i]; + // only keep going if diff === 0 + if (diff) + return diff; + i++; + } + // if the last subsegment was Static, the shorter segments should be sorted first + // otherwise sort the longest segment first + if (a.length < b.length) { + return a.length === 1 && a[0] === 40 /* PathScore.Static */ + 40 /* PathScore.Segment */ + ? -1 + : 1; + } + else if (a.length > b.length) { + return b.length === 1 && b[0] === 40 /* PathScore.Static */ + 40 /* PathScore.Segment */ + ? 1 + : -1; + } + return 0; +} +/** + * Compare function that can be used with `sort` to sort an array of PathParser + * + * @param a - first PathParser + * @param b - second PathParser + * @returns 0 if both are equal, < 0 if a should be sorted first, > 0 if b + */ +function comparePathParserScore(a, b) { + let i = 0; + const aScore = a.score; + const bScore = b.score; + while (i < aScore.length && i < bScore.length) { + const comp = compareScoreArray(aScore[i], bScore[i]); + // do not return if both are equal + if (comp) + return comp; + i++; + } + if (Math.abs(bScore.length - aScore.length) === 1) { + if (isLastScoreNegative(aScore)) + return 1; + if (isLastScoreNegative(bScore)) + return -1; + } + // if a and b share the same score entries but b has more, sort b first + return bScore.length - aScore.length; + // this is the ternary version + // return aScore.length < bScore.length + // ? 1 + // : aScore.length > bScore.length + // ? -1 + // : 0 +} +/** + * This allows detecting splats at the end of a path: /home/:id(.*)* + * + * @param score - score to check + * @returns true if the last entry is negative + */ +function isLastScoreNegative(score) { + const last = score[score.length - 1]; + return score.length > 0 && last[last.length - 1] < 0; +} + +const ROOT_TOKEN = { + type: 0 /* TokenType.Static */, + value: '', +}; +const VALID_PARAM_RE = /[a-zA-Z0-9_]/; +// After some profiling, the cache seems to be unnecessary because tokenizePath +// (the slowest part of adding a route) is very fast +// const tokenCache = new Map() +function tokenizePath(path) { + if (!path) + return [[]]; + if (path === '/') + return [[ROOT_TOKEN]]; + if (!path.startsWith('/')) { + throw new Error(`Route paths should start with a "/": "${path}" should be "/${path}".` + ); + } + // if (tokenCache.has(path)) return tokenCache.get(path)! + function crash(message) { + throw new Error(`ERR (${state})/"${buffer}": ${message}`); + } + let state = 0 /* TokenizerState.Static */; + let previousState = state; + const tokens = []; + // the segment will always be valid because we get into the initial state + // with the leading / + let segment; + function finalizeSegment() { + if (segment) + tokens.push(segment); + segment = []; + } + // index on the path + let i = 0; + // char at index + let char; + // buffer of the value read + let buffer = ''; + // custom regexp for a param + let customRe = ''; + function consumeBuffer() { + if (!buffer) + return; + if (state === 0 /* TokenizerState.Static */) { + segment.push({ + type: 0 /* TokenType.Static */, + value: buffer, + }); + } + else if (state === 1 /* TokenizerState.Param */ || + state === 2 /* TokenizerState.ParamRegExp */ || + state === 3 /* TokenizerState.ParamRegExpEnd */) { + if (segment.length > 1 && (char === '*' || char === '+')) + crash(`A repeatable param (${buffer}) must be alone in its segment. eg: '/:ids+.`); + segment.push({ + type: 1 /* TokenType.Param */, + value: buffer, + regexp: customRe, + repeatable: char === '*' || char === '+', + optional: char === '*' || char === '?', + }); + } + else { + crash('Invalid state to consume buffer'); + } + buffer = ''; + } + function addCharToBuffer() { + buffer += char; + } + while (i < path.length) { + char = path[i++]; + if (char === '\\' && state !== 2 /* TokenizerState.ParamRegExp */) { + previousState = state; + state = 4 /* TokenizerState.EscapeNext */; + continue; + } + switch (state) { + case 0 /* TokenizerState.Static */: + if (char === '/') { + if (buffer) { + consumeBuffer(); + } + finalizeSegment(); + } + else if (char === ':') { + consumeBuffer(); + state = 1 /* TokenizerState.Param */; + } + else { + addCharToBuffer(); + } + break; + case 4 /* TokenizerState.EscapeNext */: + addCharToBuffer(); + state = previousState; + break; + case 1 /* TokenizerState.Param */: + if (char === '(') { + state = 2 /* TokenizerState.ParamRegExp */; + } + else if (VALID_PARAM_RE.test(char)) { + addCharToBuffer(); + } + else { + consumeBuffer(); + state = 0 /* TokenizerState.Static */; + // go back one character if we were not modifying + if (char !== '*' && char !== '?' && char !== '+') + i--; + } + break; + case 2 /* TokenizerState.ParamRegExp */: + // TODO: is it worth handling nested regexp? like :p(?:prefix_([^/]+)_suffix) + // it already works by escaping the closing ) + // https://paths.esm.dev/?p=AAMeJbiAwQEcDKbAoAAkP60PG2R6QAvgNaA6AFACM2ABuQBB# + // is this really something people need since you can also write + // /prefix_:p()_suffix + if (char === ')') { + // handle the escaped ) + if (customRe[customRe.length - 1] == '\\') + customRe = customRe.slice(0, -1) + char; + else + state = 3 /* TokenizerState.ParamRegExpEnd */; + } + else { + customRe += char; + } + break; + case 3 /* TokenizerState.ParamRegExpEnd */: + // same as finalizing a param + consumeBuffer(); + state = 0 /* TokenizerState.Static */; + // go back one character if we were not modifying + if (char !== '*' && char !== '?' && char !== '+') + i--; + customRe = ''; + break; + default: + crash('Unknown state'); + break; + } + } + if (state === 2 /* TokenizerState.ParamRegExp */) + crash(`Unfinished custom RegExp for param "${buffer}"`); + consumeBuffer(); + finalizeSegment(); + // tokenCache.set(path, tokens) + return tokens; +} + +function createRouteRecordMatcher(record, parent, options) { + const parser = tokensToParser(tokenizePath(record.path), options); + // warn against params with the same name + { + const existingKeys = new Set(); + for (const key of parser.keys) { + if (existingKeys.has(key.name)) + warn(`Found duplicated params with name "${key.name}" for path "${record.path}". Only the last one will be available on "$route.params".`); + existingKeys.add(key.name); + } + } + const matcher = assign(parser, { + record, + parent, + // these needs to be populated by the parent + children: [], + alias: [], + }); + if (parent) { + // both are aliases or both are not aliases + // we don't want to mix them because the order is used when + // passing originalRecord in Matcher.addRoute + if (!matcher.record.aliasOf === !parent.record.aliasOf) + parent.children.push(matcher); + } + return matcher; +} + +/** + * Creates a Router Matcher. + * + * @internal + * @param routes - array of initial routes + * @param globalOptions - global route options + */ +function createRouterMatcher(routes, globalOptions) { + // normalized ordered array of matchers + const matchers = []; + const matcherMap = new Map(); + globalOptions = mergeOptions({ strict: false, end: true, sensitive: false }, globalOptions); + function getRecordMatcher(name) { + return matcherMap.get(name); + } + function addRoute(record, parent, originalRecord) { + // used later on to remove by name + const isRootAdd = !originalRecord; + const mainNormalizedRecord = normalizeRouteRecord(record); + { + checkChildMissingNameWithEmptyPath(mainNormalizedRecord, parent); + } + // we might be the child of an alias + mainNormalizedRecord.aliasOf = originalRecord && originalRecord.record; + const options = mergeOptions(globalOptions, record); + // generate an array of records to correctly handle aliases + const normalizedRecords = [ + mainNormalizedRecord, + ]; + if ('alias' in record) { + const aliases = typeof record.alias === 'string' ? [record.alias] : record.alias; + for (const alias of aliases) { + normalizedRecords.push(assign({}, mainNormalizedRecord, { + // this allows us to hold a copy of the `components` option + // so that async components cache is hold on the original record + components: originalRecord + ? originalRecord.record.components + : mainNormalizedRecord.components, + path: alias, + // we might be the child of an alias + aliasOf: originalRecord + ? originalRecord.record + : mainNormalizedRecord, + // the aliases are always of the same kind as the original since they + // are defined on the same record + })); + } + } + let matcher; + let originalMatcher; + for (const normalizedRecord of normalizedRecords) { + const { path } = normalizedRecord; + // Build up the path for nested routes if the child isn't an absolute + // route. Only add the / delimiter if the child path isn't empty and if the + // parent path doesn't have a trailing slash + if (parent && path[0] !== '/') { + const parentPath = parent.record.path; + const connectingSlash = parentPath[parentPath.length - 1] === '/' ? '' : '/'; + normalizedRecord.path = + parent.record.path + (path && connectingSlash + path); + } + if (normalizedRecord.path === '*') { + throw new Error('Catch all routes ("*") must now be defined using a param with a custom regexp.\n' + + 'See more at https://next.router.vuejs.org/guide/migration/#removed-star-or-catch-all-routes.'); + } + // create the object beforehand, so it can be passed to children + matcher = createRouteRecordMatcher(normalizedRecord, parent, options); + if (parent && path[0] === '/') + checkMissingParamsInAbsolutePath(matcher, parent); + // if we are an alias we must tell the original record that we exist, + // so we can be removed + if (originalRecord) { + originalRecord.alias.push(matcher); + { + checkSameParams(originalRecord, matcher); + } + } + else { + // otherwise, the first record is the original and others are aliases + originalMatcher = originalMatcher || matcher; + if (originalMatcher !== matcher) + originalMatcher.alias.push(matcher); + // remove the route if named and only for the top record (avoid in nested calls) + // this works because the original record is the first one + if (isRootAdd && record.name && !isAliasRecord(matcher)) + removeRoute(record.name); + } + if (mainNormalizedRecord.children) { + const children = mainNormalizedRecord.children; + for (let i = 0; i < children.length; i++) { + addRoute(children[i], matcher, originalRecord && originalRecord.children[i]); + } + } + // if there was no original record, then the first one was not an alias and all + // other aliases (if any) need to reference this record when adding children + originalRecord = originalRecord || matcher; + // TODO: add normalized records for more flexibility + // if (parent && isAliasRecord(originalRecord)) { + // parent.children.push(originalRecord) + // } + // Avoid adding a record that doesn't display anything. This allows passing through records without a component to + // not be reached and pass through the catch all route + if ((matcher.record.components && + Object.keys(matcher.record.components).length) || + matcher.record.name || + matcher.record.redirect) { + insertMatcher(matcher); + } + } + return originalMatcher + ? () => { + // since other matchers are aliases, they should be removed by the original matcher + removeRoute(originalMatcher); + } + : noop; + } + function removeRoute(matcherRef) { + if (isRouteName(matcherRef)) { + const matcher = matcherMap.get(matcherRef); + if (matcher) { + matcherMap.delete(matcherRef); + matchers.splice(matchers.indexOf(matcher), 1); + matcher.children.forEach(removeRoute); + matcher.alias.forEach(removeRoute); + } + } + else { + const index = matchers.indexOf(matcherRef); + if (index > -1) { + matchers.splice(index, 1); + if (matcherRef.record.name) + matcherMap.delete(matcherRef.record.name); + matcherRef.children.forEach(removeRoute); + matcherRef.alias.forEach(removeRoute); + } + } + } + function getRoutes() { + return matchers; + } + function insertMatcher(matcher) { + let i = 0; + while (i < matchers.length && + comparePathParserScore(matcher, matchers[i]) >= 0 && + // Adding children with empty path should still appear before the parent + // https://github.com/vuejs/router/issues/1124 + (matcher.record.path !== matchers[i].record.path || + !isRecordChildOf(matcher, matchers[i]))) + i++; + matchers.splice(i, 0, matcher); + // only add the original record to the name map + if (matcher.record.name && !isAliasRecord(matcher)) + matcherMap.set(matcher.record.name, matcher); + } + function resolve(location, currentLocation) { + let matcher; + let params = {}; + let path; + let name; + if ('name' in location && location.name) { + matcher = matcherMap.get(location.name); + if (!matcher) + throw createRouterError(1 /* ErrorTypes.MATCHER_NOT_FOUND */, { + location, + }); + // warn if the user is passing invalid params so they can debug it better when they get removed + { + const invalidParams = Object.keys(location.params || {}).filter(paramName => !matcher.keys.find(k => k.name === paramName)); + if (invalidParams.length) { + warn(`Discarded invalid param(s) "${invalidParams.join('", "')}" when navigating. See https://github.com/vuejs/router/blob/main/packages/router/CHANGELOG.md#414-2022-08-22 for more details.`); + } + } + name = matcher.record.name; + params = assign( + // paramsFromLocation is a new object + paramsFromLocation(currentLocation.params, + // only keep params that exist in the resolved location + // TODO: only keep optional params coming from a parent record + matcher.keys.filter(k => !k.optional).map(k => k.name)), + // discard any existing params in the current location that do not exist here + // #1497 this ensures better active/exact matching + location.params && + paramsFromLocation(location.params, matcher.keys.map(k => k.name))); + // throws if cannot be stringified + path = matcher.stringify(params); + } + else if ('path' in location) { + // no need to resolve the path with the matcher as it was provided + // this also allows the user to control the encoding + path = location.path; + if (!path.startsWith('/')) { + warn(`The Matcher cannot resolve relative paths but received "${path}". Unless you directly called \`matcher.resolve("${path}")\`, this is probably a bug in vue-router. Please open an issue at https://github.com/vuejs/router/issues/new/choose.`); + } + matcher = matchers.find(m => m.re.test(path)); + // matcher should have a value after the loop + if (matcher) { + // we know the matcher works because we tested the regexp + params = matcher.parse(path); + name = matcher.record.name; + } + // location is a relative path + } + else { + // match by name or path of current route + matcher = currentLocation.name + ? matcherMap.get(currentLocation.name) + : matchers.find(m => m.re.test(currentLocation.path)); + if (!matcher) + throw createRouterError(1 /* ErrorTypes.MATCHER_NOT_FOUND */, { + location, + currentLocation, + }); + name = matcher.record.name; + // since we are navigating to the same location, we don't need to pick the + // params like when `name` is provided + params = assign({}, currentLocation.params, location.params); + path = matcher.stringify(params); + } + const matched = []; + let parentMatcher = matcher; + while (parentMatcher) { + // reversed order so parents are at the beginning + matched.unshift(parentMatcher.record); + parentMatcher = parentMatcher.parent; + } + return { + name, + path, + params, + matched, + meta: mergeMetaFields(matched), + }; + } + // add initial routes + routes.forEach(route => addRoute(route)); + return { addRoute, resolve, removeRoute, getRoutes, getRecordMatcher }; +} +function paramsFromLocation(params, keys) { + const newParams = {}; + for (const key of keys) { + if (key in params) + newParams[key] = params[key]; + } + return newParams; +} +/** + * Normalizes a RouteRecordRaw. Creates a copy + * + * @param record + * @returns the normalized version + */ +function normalizeRouteRecord(record) { + return { + path: record.path, + redirect: record.redirect, + name: record.name, + meta: record.meta || {}, + aliasOf: undefined, + beforeEnter: record.beforeEnter, + props: normalizeRecordProps(record), + children: record.children || [], + instances: {}, + leaveGuards: new Set(), + updateGuards: new Set(), + enterCallbacks: {}, + components: 'components' in record + ? record.components || null + : record.component && { default: record.component }, + }; +} +/** + * Normalize the optional `props` in a record to always be an object similar to + * components. Also accept a boolean for components. + * @param record + */ +function normalizeRecordProps(record) { + const propsObject = {}; + // props does not exist on redirect records, but we can set false directly + const props = record.props || false; + if ('component' in record) { + propsObject.default = props; + } + else { + // NOTE: we could also allow a function to be applied to every component. + // Would need user feedback for use cases + for (const name in record.components) + propsObject[name] = typeof props === 'object' ? props[name] : props; + } + return propsObject; +} +/** + * Checks if a record or any of its parent is an alias + * @param record + */ +function isAliasRecord(record) { + while (record) { + if (record.record.aliasOf) + return true; + record = record.parent; + } + return false; +} +/** + * Merge meta fields of an array of records + * + * @param matched - array of matched records + */ +function mergeMetaFields(matched) { + return matched.reduce((meta, record) => assign(meta, record.meta), {}); +} +function mergeOptions(defaults, partialOptions) { + const options = {}; + for (const key in defaults) { + options[key] = key in partialOptions ? partialOptions[key] : defaults[key]; + } + return options; +} +function isSameParam(a, b) { + return (a.name === b.name && + a.optional === b.optional && + a.repeatable === b.repeatable); +} +/** + * Check if a path and its alias have the same required params + * + * @param a - original record + * @param b - alias record + */ +function checkSameParams(a, b) { + for (const key of a.keys) { + if (!key.optional && !b.keys.find(isSameParam.bind(null, key))) + return warn(`Alias "${b.record.path}" and the original record: "${a.record.path}" must have the exact same param named "${key.name}"`); + } + for (const key of b.keys) { + if (!key.optional && !a.keys.find(isSameParam.bind(null, key))) + return warn(`Alias "${b.record.path}" and the original record: "${a.record.path}" must have the exact same param named "${key.name}"`); + } +} +/** + * A route with a name and a child with an empty path without a name should warn when adding the route + * + * @param mainNormalizedRecord - RouteRecordNormalized + * @param parent - RouteRecordMatcher + */ +function checkChildMissingNameWithEmptyPath(mainNormalizedRecord, parent) { + if (parent && + parent.record.name && + !mainNormalizedRecord.name && + !mainNormalizedRecord.path) { + warn(`The route named "${String(parent.record.name)}" has a child without a name and an empty path. Using that name won't render the empty path child so you probably want to move the name to the child instead. If this is intentional, add a name to the child route to remove the warning.`); + } +} +function checkMissingParamsInAbsolutePath(record, parent) { + for (const key of parent.keys) { + if (!record.keys.find(isSameParam.bind(null, key))) + return warn(`Absolute path "${record.record.path}" must have the exact same param named "${key.name}" as its parent "${parent.record.path}".`); + } +} +function isRecordChildOf(record, parent) { + return parent.children.some(child => child === record || isRecordChildOf(record, child)); +} + +/** + * Encoding Rules ⣠= Space Path: ⣠" < > # ? { } Query: ⣠" < > # & = Hash: ⣠" + * < > ` + * + * On top of that, the RFC3986 (https://tools.ietf.org/html/rfc3986#section-2.2) + * defines some extra characters to be encoded. Most browsers do not encode them + * in encodeURI https://github.com/whatwg/url/issues/369, so it may be safer to + * also encode `!'()*`. Leaving un-encoded only ASCII alphanumeric(`a-zA-Z0-9`) + * plus `-._~`. This extra safety should be applied to query by patching the + * string returned by encodeURIComponent encodeURI also encodes `[\]^`. `\` + * should be encoded to avoid ambiguity. Browsers (IE, FF, C) transform a `\` + * into a `/` if directly typed in. The _backtick_ (`````) should also be + * encoded everywhere because some browsers like FF encode it when directly + * written while others don't. Safari and IE don't encode ``"<>{}``` in hash. + */ +// const EXTRA_RESERVED_RE = /[!'()*]/g +// const encodeReservedReplacer = (c: string) => '%' + c.charCodeAt(0).toString(16) +const HASH_RE = /#/g; // %23 +const AMPERSAND_RE = /&/g; // %26 +const SLASH_RE = /\//g; // %2F +const EQUAL_RE = /=/g; // %3D +const IM_RE = /\?/g; // %3F +const PLUS_RE = /\+/g; // %2B +/** + * NOTE: It's not clear to me if we should encode the + symbol in queries, it + * seems to be less flexible than not doing so and I can't find out the legacy + * systems requiring this for regular requests like text/html. In the standard, + * the encoding of the plus character is only mentioned for + * application/x-www-form-urlencoded + * (https://url.spec.whatwg.org/#urlencoded-parsing) and most browsers seems lo + * leave the plus character as is in queries. To be more flexible, we allow the + * plus character on the query, but it can also be manually encoded by the user. + * + * Resources: + * - https://url.spec.whatwg.org/#urlencoded-parsing + * - https://stackoverflow.com/questions/1634271/url-encoding-the-space-character-or-20 + */ +const ENC_BRACKET_OPEN_RE = /%5B/g; // [ +const ENC_BRACKET_CLOSE_RE = /%5D/g; // ] +const ENC_CARET_RE = /%5E/g; // ^ +const ENC_BACKTICK_RE = /%60/g; // ` +const ENC_CURLY_OPEN_RE = /%7B/g; // { +const ENC_PIPE_RE = /%7C/g; // | +const ENC_CURLY_CLOSE_RE = /%7D/g; // } +const ENC_SPACE_RE = /%20/g; // } +/** + * Encode characters that need to be encoded on the path, search and hash + * sections of the URL. + * + * @internal + * @param text - string to encode + * @returns encoded string + */ +function commonEncode(text) { + return encodeURI('' + text) + .replace(ENC_PIPE_RE, '|') + .replace(ENC_BRACKET_OPEN_RE, '[') + .replace(ENC_BRACKET_CLOSE_RE, ']'); +} +/** + * Encode characters that need to be encoded on the hash section of the URL. + * + * @param text - string to encode + * @returns encoded string + */ +function encodeHash(text) { + return commonEncode(text) + .replace(ENC_CURLY_OPEN_RE, '{') + .replace(ENC_CURLY_CLOSE_RE, '}') + .replace(ENC_CARET_RE, '^'); +} +/** + * Encode characters that need to be encoded query values on the query + * section of the URL. + * + * @param text - string to encode + * @returns encoded string + */ +function encodeQueryValue(text) { + return (commonEncode(text) + // Encode the space as +, encode the + to differentiate it from the space + .replace(PLUS_RE, '%2B') + .replace(ENC_SPACE_RE, '+') + .replace(HASH_RE, '%23') + .replace(AMPERSAND_RE, '%26') + .replace(ENC_BACKTICK_RE, '`') + .replace(ENC_CURLY_OPEN_RE, '{') + .replace(ENC_CURLY_CLOSE_RE, '}') + .replace(ENC_CARET_RE, '^')); +} +/** + * Like `encodeQueryValue` but also encodes the `=` character. + * + * @param text - string to encode + */ +function encodeQueryKey(text) { + return encodeQueryValue(text).replace(EQUAL_RE, '%3D'); +} +/** + * Encode characters that need to be encoded on the path section of the URL. + * + * @param text - string to encode + * @returns encoded string + */ +function encodePath(text) { + return commonEncode(text).replace(HASH_RE, '%23').replace(IM_RE, '%3F'); +} +/** + * Encode characters that need to be encoded on the path section of the URL as a + * param. This function encodes everything {@link encodePath} does plus the + * slash (`/`) character. If `text` is `null` or `undefined`, returns an empty + * string instead. + * + * @param text - string to encode + * @returns encoded string + */ +function encodeParam(text) { + return text == null ? '' : encodePath(text).replace(SLASH_RE, '%2F'); +} +/** + * Decode text using `decodeURIComponent`. Returns the original text if it + * fails. + * + * @param text - string to decode + * @returns decoded string + */ +function decode(text) { + try { + return decodeURIComponent('' + text); + } + catch (err) { + warn(`Error decoding "${text}". Using original value`); + } + return '' + text; +} + +/** + * Transforms a queryString into a {@link LocationQuery} object. Accept both, a + * version with the leading `?` and without Should work as URLSearchParams + + * @internal + * + * @param search - search string to parse + * @returns a query object + */ +function parseQuery(search) { + const query = {}; + // avoid creating an object with an empty key and empty value + // because of split('&') + if (search === '' || search === '?') + return query; + const hasLeadingIM = search[0] === '?'; + const searchParams = (hasLeadingIM ? search.slice(1) : search).split('&'); + for (let i = 0; i < searchParams.length; ++i) { + // pre decode the + into space + const searchParam = searchParams[i].replace(PLUS_RE, ' '); + // allow the = character + const eqPos = searchParam.indexOf('='); + const key = decode(eqPos < 0 ? searchParam : searchParam.slice(0, eqPos)); + const value = eqPos < 0 ? null : decode(searchParam.slice(eqPos + 1)); + if (key in query) { + // an extra variable for ts types + let currentValue = query[key]; + if (!isArray(currentValue)) { + currentValue = query[key] = [currentValue]; + } + currentValue.push(value); + } + else { + query[key] = value; + } + } + return query; +} +/** + * Stringifies a {@link LocationQueryRaw} object. Like `URLSearchParams`, it + * doesn't prepend a `?` + * + * @internal + * + * @param query - query object to stringify + * @returns string version of the query without the leading `?` + */ +function stringifyQuery(query) { + let search = ''; + for (let key in query) { + const value = query[key]; + key = encodeQueryKey(key); + if (value == null) { + // only null adds the value + if (value !== undefined) { + search += (search.length ? '&' : '') + key; + } + continue; + } + // keep null values + const values = isArray(value) + ? value.map(v => v && encodeQueryValue(v)) + : [value && encodeQueryValue(value)]; + values.forEach(value => { + // skip undefined values in arrays as if they were not present + // smaller code than using filter + if (value !== undefined) { + // only append & with non-empty search + search += (search.length ? '&' : '') + key; + if (value != null) + search += '=' + value; + } + }); + } + return search; +} +/** + * Transforms a {@link LocationQueryRaw} into a {@link LocationQuery} by casting + * numbers into strings, removing keys with an undefined value and replacing + * undefined with null in arrays + * + * @param query - query object to normalize + * @returns a normalized query object + */ +function normalizeQuery(query) { + const normalizedQuery = {}; + for (const key in query) { + const value = query[key]; + if (value !== undefined) { + normalizedQuery[key] = isArray(value) + ? value.map(v => (v == null ? null : '' + v)) + : value == null + ? value + : '' + value; + } + } + return normalizedQuery; +} + +/** + * RouteRecord being rendered by the closest ancestor Router View. Used for + * `onBeforeRouteUpdate` and `onBeforeRouteLeave`. rvlm stands for Router View + * Location Matched + * + * @internal + */ +const matchedRouteKey = Symbol('router view location matched' ); +/** + * Allows overriding the router view depth to control which component in + * `matched` is rendered. rvd stands for Router View Depth + * + * @internal + */ +const viewDepthKey = Symbol('router view depth' ); +/** + * Allows overriding the router instance returned by `useRouter` in tests. r + * stands for router + * + * @internal + */ +const routerKey = Symbol('router' ); +/** + * Allows overriding the current route returned by `useRoute` in tests. rl + * stands for route location + * + * @internal + */ +const routeLocationKey = Symbol('route location' ); +/** + * Allows overriding the current route used by router-view. Internally this is + * used when the `route` prop is passed. + * + * @internal + */ +const routerViewLocationKey = Symbol('router view location' ); + +/** + * Create a list of callbacks that can be reset. Used to create before and after navigation guards list + */ +function useCallbacks() { + let handlers = []; + function add(handler) { + handlers.push(handler); + return () => { + const i = handlers.indexOf(handler); + if (i > -1) + handlers.splice(i, 1); + }; + } + function reset() { + handlers = []; + } + return { + add, + list: () => handlers.slice(), + reset, + }; +} + +function registerGuard(record, name, guard) { + const removeFromList = () => { + record[name].delete(guard); + }; + onUnmounted(removeFromList); + onDeactivated(removeFromList); + onActivated(() => { + record[name].add(guard); + }); + record[name].add(guard); +} +/** + * Add a navigation guard that triggers whenever the component for the current + * location is about to be left. Similar to {@link beforeRouteLeave} but can be + * used in any component. The guard is removed when the component is unmounted. + * + * @param leaveGuard - {@link NavigationGuard} + */ +function onBeforeRouteLeave(leaveGuard) { + if (!getCurrentInstance()) { + warn('getCurrentInstance() returned null. onBeforeRouteLeave() must be called at the top of a setup function'); + return; + } + const activeRecord = inject(matchedRouteKey, + // to avoid warning + {}).value; + if (!activeRecord) { + warn('No active route record was found when calling `onBeforeRouteLeave()`. Make sure you call this function inside a component child of . Maybe you called it inside of App.vue?'); + return; + } + registerGuard(activeRecord, 'leaveGuards', leaveGuard); +} +/** + * Add a navigation guard that triggers whenever the current location is about + * to be updated. Similar to {@link beforeRouteUpdate} but can be used in any + * component. The guard is removed when the component is unmounted. + * + * @param updateGuard - {@link NavigationGuard} + */ +function onBeforeRouteUpdate(updateGuard) { + if (!getCurrentInstance()) { + warn('getCurrentInstance() returned null. onBeforeRouteUpdate() must be called at the top of a setup function'); + return; + } + const activeRecord = inject(matchedRouteKey, + // to avoid warning + {}).value; + if (!activeRecord) { + warn('No active route record was found when calling `onBeforeRouteUpdate()`. Make sure you call this function inside a component child of . Maybe you called it inside of App.vue?'); + return; + } + registerGuard(activeRecord, 'updateGuards', updateGuard); +} +function guardToPromiseFn(guard, to, from, record, name) { + // keep a reference to the enterCallbackArray to prevent pushing callbacks if a new navigation took place + const enterCallbackArray = record && + // name is defined if record is because of the function overload + (record.enterCallbacks[name] = record.enterCallbacks[name] || []); + return () => new Promise((resolve, reject) => { + const next = (valid) => { + if (valid === false) { + reject(createRouterError(4 /* ErrorTypes.NAVIGATION_ABORTED */, { + from, + to, + })); + } + else if (valid instanceof Error) { + reject(valid); + } + else if (isRouteLocation(valid)) { + reject(createRouterError(2 /* ErrorTypes.NAVIGATION_GUARD_REDIRECT */, { + from: to, + to: valid, + })); + } + else { + if (enterCallbackArray && + // since enterCallbackArray is truthy, both record and name also are + record.enterCallbacks[name] === enterCallbackArray && + typeof valid === 'function') { + enterCallbackArray.push(valid); + } + resolve(); + } + }; + // wrapping with Promise.resolve allows it to work with both async and sync guards + const guardReturn = guard.call(record && record.instances[name], to, from, canOnlyBeCalledOnce(next, to, from) ); + let guardCall = Promise.resolve(guardReturn); + if (guard.length < 3) + guardCall = guardCall.then(next); + if (guard.length > 2) { + const message = `The "next" callback was never called inside of ${guard.name ? '"' + guard.name + '"' : ''}:\n${guard.toString()}\n. If you are returning a value instead of calling "next", make sure to remove the "next" parameter from your function.`; + if (typeof guardReturn === 'object' && 'then' in guardReturn) { + guardCall = guardCall.then(resolvedValue => { + // @ts-expect-error: _called is added at canOnlyBeCalledOnce + if (!next._called) { + warn(message); + return Promise.reject(new Error('Invalid navigation guard')); + } + return resolvedValue; + }); + } + else if (guardReturn !== undefined) { + // @ts-expect-error: _called is added at canOnlyBeCalledOnce + if (!next._called) { + warn(message); + reject(new Error('Invalid navigation guard')); + return; + } + } + } + guardCall.catch(err => reject(err)); + }); +} +function canOnlyBeCalledOnce(next, to, from) { + let called = 0; + return function () { + if (called++ === 1) + warn(`The "next" callback was called more than once in one navigation guard when going from "${from.fullPath}" to "${to.fullPath}". It should be called exactly one time in each navigation guard. This will fail in production.`); + // @ts-expect-error: we put it in the original one because it's easier to check + next._called = true; + if (called === 1) + next.apply(null, arguments); + }; +} +function extractComponentsGuards(matched, guardType, to, from) { + const guards = []; + for (const record of matched) { + if (!record.components && !record.children.length) { + warn(`Record with path "${record.path}" is either missing a "component(s)"` + + ` or "children" property.`); + } + for (const name in record.components) { + let rawComponent = record.components[name]; + { + if (!rawComponent || + (typeof rawComponent !== 'object' && + typeof rawComponent !== 'function')) { + warn(`Component "${name}" in record with path "${record.path}" is not` + + ` a valid component. Received "${String(rawComponent)}".`); + // throw to ensure we stop here but warn to ensure the message isn't + // missed by the user + throw new Error('Invalid route component'); + } + else if ('then' in rawComponent) { + // warn if user wrote import('/component.vue') instead of () => + // import('./component.vue') + warn(`Component "${name}" in record with path "${record.path}" is a ` + + `Promise instead of a function that returns a Promise. Did you ` + + `write "import('./MyPage.vue')" instead of ` + + `"() => import('./MyPage.vue')" ? This will break in ` + + `production if not fixed.`); + const promise = rawComponent; + rawComponent = () => promise; + } + else if (rawComponent.__asyncLoader && + // warn only once per component + !rawComponent.__warnedDefineAsync) { + rawComponent.__warnedDefineAsync = true; + warn(`Component "${name}" in record with path "${record.path}" is defined ` + + `using "defineAsyncComponent()". ` + + `Write "() => import('./MyPage.vue')" instead of ` + + `"defineAsyncComponent(() => import('./MyPage.vue'))".`); + } + } + // skip update and leave guards if the route component is not mounted + if (guardType !== 'beforeRouteEnter' && !record.instances[name]) + continue; + if (isRouteComponent(rawComponent)) { + // __vccOpts is added by vue-class-component and contain the regular options + const options = rawComponent.__vccOpts || rawComponent; + const guard = options[guardType]; + guard && guards.push(guardToPromiseFn(guard, to, from, record, name)); + } + else { + // start requesting the chunk already + let componentPromise = rawComponent(); + if (!('catch' in componentPromise)) { + warn(`Component "${name}" in record with path "${record.path}" is a function that does not return a Promise. If you were passing a functional component, make sure to add a "displayName" to the component. This will break in production if not fixed.`); + componentPromise = Promise.resolve(componentPromise); + } + guards.push(() => componentPromise.then(resolved => { + if (!resolved) + return Promise.reject(new Error(`Couldn't resolve component "${name}" at "${record.path}"`)); + const resolvedComponent = isESModule(resolved) + ? resolved.default + : resolved; + // replace the function with the resolved component + // cannot be null or undefined because we went into the for loop + record.components[name] = resolvedComponent; + // __vccOpts is added by vue-class-component and contain the regular options + const options = resolvedComponent.__vccOpts || resolvedComponent; + const guard = options[guardType]; + return guard && guardToPromiseFn(guard, to, from, record, name)(); + })); + } + } + } + return guards; +} +/** + * Allows differentiating lazy components from functional components and vue-class-component + * @internal + * + * @param component + */ +function isRouteComponent(component) { + return (typeof component === 'object' || + 'displayName' in component || + 'props' in component || + '__vccOpts' in component); +} +/** + * Ensures a route is loaded, so it can be passed as o prop to ``. + * + * @param route - resolved route to load + */ +function loadRouteLocation(route) { + return route.matched.every(record => record.redirect) + ? Promise.reject(new Error('Cannot load a route that redirects.')) + : Promise.all(route.matched.map(record => record.components && + Promise.all(Object.keys(record.components).reduce((promises, name) => { + const rawComponent = record.components[name]; + if (typeof rawComponent === 'function' && + !('displayName' in rawComponent)) { + promises.push(rawComponent().then(resolved => { + if (!resolved) + return Promise.reject(new Error(`Couldn't resolve component "${name}" at "${record.path}". Ensure you passed a function that returns a promise.`)); + const resolvedComponent = isESModule(resolved) + ? resolved.default + : resolved; + // replace the function with the resolved component + // cannot be null or undefined because we went into the for loop + record.components[name] = resolvedComponent; + return; + })); + } + return promises; + }, [])))).then(() => route); +} + +// TODO: we could allow currentRoute as a prop to expose `isActive` and +// `isExactActive` behavior should go through an RFC +function useLink(props) { + const router = inject(routerKey); + const currentRoute = inject(routeLocationKey); + const route = computed(() => router.resolve(unref(props.to))); + const activeRecordIndex = computed(() => { + const { matched } = route.value; + const { length } = matched; + const routeMatched = matched[length - 1]; + const currentMatched = currentRoute.matched; + if (!routeMatched || !currentMatched.length) + return -1; + const index = currentMatched.findIndex(isSameRouteRecord.bind(null, routeMatched)); + if (index > -1) + return index; + // possible parent record + const parentRecordPath = getOriginalPath(matched[length - 2]); + return ( + // we are dealing with nested routes + length > 1 && + // if the parent and matched route have the same path, this link is + // referring to the empty child. Or we currently are on a different + // child of the same parent + getOriginalPath(routeMatched) === parentRecordPath && + // avoid comparing the child with its parent + currentMatched[currentMatched.length - 1].path !== parentRecordPath + ? currentMatched.findIndex(isSameRouteRecord.bind(null, matched[length - 2])) + : index); + }); + const isActive = computed(() => activeRecordIndex.value > -1 && + includesParams(currentRoute.params, route.value.params)); + const isExactActive = computed(() => activeRecordIndex.value > -1 && + activeRecordIndex.value === currentRoute.matched.length - 1 && + isSameRouteLocationParams(currentRoute.params, route.value.params)); + function navigate(e = {}) { + if (guardEvent(e)) { + return router[unref(props.replace) ? 'replace' : 'push'](unref(props.to) + // avoid uncaught errors are they are logged anyway + ).catch(noop); + } + return Promise.resolve(); + } + // devtools only + if (isBrowser) { + const instance = getCurrentInstance(); + if (instance) { + const linkContextDevtools = { + route: route.value, + isActive: isActive.value, + isExactActive: isExactActive.value, + }; + // @ts-expect-error: this is internal + instance.__vrl_devtools = instance.__vrl_devtools || []; + // @ts-expect-error: this is internal + instance.__vrl_devtools.push(linkContextDevtools); + watchEffect(() => { + linkContextDevtools.route = route.value; + linkContextDevtools.isActive = isActive.value; + linkContextDevtools.isExactActive = isExactActive.value; + }, { flush: 'post' }); + } + } + /** + * NOTE: update {@link _RouterLinkI}'s `$slots` type when updating this + */ + return { + route, + href: computed(() => route.value.href), + isActive, + isExactActive, + navigate, + }; +} +const RouterLinkImpl = /*#__PURE__*/ defineComponent({ + name: 'RouterLink', + compatConfig: { MODE: 3 }, + props: { + to: { + type: [String, Object], + required: true, + }, + replace: Boolean, + activeClass: String, + // inactiveClass: String, + exactActiveClass: String, + custom: Boolean, + ariaCurrentValue: { + type: String, + default: 'page', + }, + }, + useLink, + setup(props, { slots }) { + const link = reactive(useLink(props)); + const { options } = inject(routerKey); + const elClass = computed(() => ({ + [getLinkClass(props.activeClass, options.linkActiveClass, 'router-link-active')]: link.isActive, + // [getLinkClass( + // props.inactiveClass, + // options.linkInactiveClass, + // 'router-link-inactive' + // )]: !link.isExactActive, + [getLinkClass(props.exactActiveClass, options.linkExactActiveClass, 'router-link-exact-active')]: link.isExactActive, + })); + return () => { + const children = slots.default && slots.default(link); + return props.custom + ? children + : h('a', { + 'aria-current': link.isExactActive + ? props.ariaCurrentValue + : null, + href: link.href, + // this would override user added attrs but Vue will still add + // the listener, so we end up triggering both + onClick: link.navigate, + class: elClass.value, + }, children); + }; + }, +}); +// export the public type for h/tsx inference +// also to avoid inline import() in generated d.ts files +/** + * Component to render a link that triggers a navigation on click. + */ +const RouterLink = RouterLinkImpl; +function guardEvent(e) { + // don't redirect with control keys + if (e.metaKey || e.altKey || e.ctrlKey || e.shiftKey) + return; + // don't redirect when preventDefault called + if (e.defaultPrevented) + return; + // don't redirect on right click + if (e.button !== undefined && e.button !== 0) + return; + // don't redirect if `target="_blank"` + // @ts-expect-error getAttribute does exist + if (e.currentTarget && e.currentTarget.getAttribute) { + // @ts-expect-error getAttribute exists + const target = e.currentTarget.getAttribute('target'); + if (/\b_blank\b/i.test(target)) + return; + } + // this may be a Weex event which doesn't have this method + if (e.preventDefault) + e.preventDefault(); + return true; +} +function includesParams(outer, inner) { + for (const key in inner) { + const innerValue = inner[key]; + const outerValue = outer[key]; + if (typeof innerValue === 'string') { + if (innerValue !== outerValue) + return false; + } + else { + if (!isArray(outerValue) || + outerValue.length !== innerValue.length || + innerValue.some((value, i) => value !== outerValue[i])) + return false; + } + } + return true; +} +/** + * Get the original path value of a record by following its aliasOf + * @param record + */ +function getOriginalPath(record) { + return record ? (record.aliasOf ? record.aliasOf.path : record.path) : ''; +} +/** + * Utility class to get the active class based on defaults. + * @param propClass + * @param globalClass + * @param defaultClass + */ +const getLinkClass = (propClass, globalClass, defaultClass) => propClass != null + ? propClass + : globalClass != null + ? globalClass + : defaultClass; + +const RouterViewImpl = /*#__PURE__*/ defineComponent({ + name: 'RouterView', + // #674 we manually inherit them + inheritAttrs: false, + props: { + name: { + type: String, + default: 'default', + }, + route: Object, + }, + // Better compat for @vue/compat users + // https://github.com/vuejs/router/issues/1315 + compatConfig: { MODE: 3 }, + setup(props, { attrs, slots }) { + warnDeprecatedUsage(); + const injectedRoute = inject(routerViewLocationKey); + const routeToDisplay = computed(() => props.route || injectedRoute.value); + const injectedDepth = inject(viewDepthKey, 0); + // The depth changes based on empty components option, which allows passthrough routes e.g. routes with children + // that are used to reuse the `path` property + const depth = computed(() => { + let initialDepth = unref(injectedDepth); + const { matched } = routeToDisplay.value; + let matchedRoute; + while ((matchedRoute = matched[initialDepth]) && + !matchedRoute.components) { + initialDepth++; + } + return initialDepth; + }); + const matchedRouteRef = computed(() => routeToDisplay.value.matched[depth.value]); + provide(viewDepthKey, computed(() => depth.value + 1)); + provide(matchedRouteKey, matchedRouteRef); + provide(routerViewLocationKey, routeToDisplay); + const viewRef = ref(); + // watch at the same time the component instance, the route record we are + // rendering, and the name + watch(() => [viewRef.value, matchedRouteRef.value, props.name], ([instance, to, name], [oldInstance, from, oldName]) => { + // copy reused instances + if (to) { + // this will update the instance for new instances as well as reused + // instances when navigating to a new route + to.instances[name] = instance; + // the component instance is reused for a different route or name, so + // we copy any saved update or leave guards. With async setup, the + // mounting component will mount before the matchedRoute changes, + // making instance === oldInstance, so we check if guards have been + // added before. This works because we remove guards when + // unmounting/deactivating components + if (from && from !== to && instance && instance === oldInstance) { + if (!to.leaveGuards.size) { + to.leaveGuards = from.leaveGuards; + } + if (!to.updateGuards.size) { + to.updateGuards = from.updateGuards; + } + } + } + // trigger beforeRouteEnter next callbacks + if (instance && + to && + // if there is no instance but to and from are the same this might be + // the first visit + (!from || !isSameRouteRecord(to, from) || !oldInstance)) { + (to.enterCallbacks[name] || []).forEach(callback => callback(instance)); + } + }, { flush: 'post' }); + return () => { + const route = routeToDisplay.value; + // we need the value at the time we render because when we unmount, we + // navigated to a different location so the value is different + const currentName = props.name; + const matchedRoute = matchedRouteRef.value; + const ViewComponent = matchedRoute && matchedRoute.components[currentName]; + if (!ViewComponent) { + return normalizeSlot(slots.default, { Component: ViewComponent, route }); + } + // props from route configuration + const routePropsOption = matchedRoute.props[currentName]; + const routeProps = routePropsOption + ? routePropsOption === true + ? route.params + : typeof routePropsOption === 'function' + ? routePropsOption(route) + : routePropsOption + : null; + const onVnodeUnmounted = vnode => { + // remove the instance reference to prevent leak + if (vnode.component.isUnmounted) { + matchedRoute.instances[currentName] = null; + } + }; + const component = h(ViewComponent, assign({}, routeProps, attrs, { + onVnodeUnmounted, + ref: viewRef, + })); + if (isBrowser && + component.ref) { + // TODO: can display if it's an alias, its props + const info = { + depth: depth.value, + name: matchedRoute.name, + path: matchedRoute.path, + meta: matchedRoute.meta, + }; + const internalInstances = isArray(component.ref) + ? component.ref.map(r => r.i) + : [component.ref.i]; + internalInstances.forEach(instance => { + // @ts-expect-error + instance.__vrv_devtools = info; + }); + } + return ( + // pass the vnode to the slot as a prop. + // h and both accept vnodes + normalizeSlot(slots.default, { Component: component, route }) || + component); + }; + }, +}); +function normalizeSlot(slot, data) { + if (!slot) + return null; + const slotContent = slot(data); + return slotContent.length === 1 ? slotContent[0] : slotContent; +} +// export the public type for h/tsx inference +// also to avoid inline import() in generated d.ts files +/** + * Component to display the current route the user is at. + */ +const RouterView = RouterViewImpl; +// warn against deprecated usage with & +// due to functional component being no longer eager in Vue 3 +function warnDeprecatedUsage() { + const instance = getCurrentInstance(); + const parentName = instance.parent && instance.parent.type.name; + const parentSubTreeType = instance.parent && instance.parent.subTree && instance.parent.subTree.type; + if (parentName && + (parentName === 'KeepAlive' || parentName.includes('Transition')) && + typeof parentSubTreeType === 'object' && + parentSubTreeType.name === 'RouterView') { + const comp = parentName === 'KeepAlive' ? 'keep-alive' : 'transition'; + warn(` can no longer be used directly inside or .\n` + + `Use slot props instead:\n\n` + + `\n` + + ` <${comp}>\n` + + ` \n` + + ` \n` + + ``); + } +} + +/** + * Copies a route location and removes any problematic properties that cannot be shown in devtools (e.g. Vue instances). + * + * @param routeLocation - routeLocation to format + * @param tooltip - optional tooltip + * @returns a copy of the routeLocation + */ +function formatRouteLocation(routeLocation, tooltip) { + const copy = assign({}, routeLocation, { + // remove variables that can contain vue instances + matched: routeLocation.matched.map(matched => omit(matched, ['instances', 'children', 'aliasOf'])), + }); + return { + _custom: { + type: null, + readOnly: true, + display: routeLocation.fullPath, + tooltip, + value: copy, + }, + }; +} +function formatDisplay(display) { + return { + _custom: { + display, + }, + }; +} +// to support multiple router instances +let routerId = 0; +function addDevtools(app, router, matcher) { + // Take over router.beforeEach and afterEach + // make sure we are not registering the devtool twice + if (router.__hasDevtools) + return; + router.__hasDevtools = true; + // increment to support multiple router instances + const id = routerId++; + setupDevtoolsPlugin({ + id: 'org.vuejs.router' + (id ? '.' + id : ''), + label: 'Vue Router', + packageName: 'vue-router', + homepage: 'https://router.vuejs.org', + logo: 'https://router.vuejs.org/logo.png', + componentStateTypes: ['Routing'], + app, + }, api => { + if (typeof api.now !== 'function') { + console.warn('[Vue Router]: You seem to be using an outdated version of Vue Devtools. Are you still using the Beta release instead of the stable one? You can find the links at https://devtools.vuejs.org/guide/installation.html.'); + } + // display state added by the router + api.on.inspectComponent((payload, ctx) => { + if (payload.instanceData) { + payload.instanceData.state.push({ + type: 'Routing', + key: '$route', + editable: false, + value: formatRouteLocation(router.currentRoute.value, 'Current Route'), + }); + } + }); + // mark router-link as active and display tags on router views + api.on.visitComponentTree(({ treeNode: node, componentInstance }) => { + if (componentInstance.__vrv_devtools) { + const info = componentInstance.__vrv_devtools; + node.tags.push({ + label: (info.name ? `${info.name.toString()}: ` : '') + info.path, + textColor: 0, + tooltip: 'This component is rendered by <router-view>', + backgroundColor: PINK_500, + }); + } + // if multiple useLink are used + if (isArray(componentInstance.__vrl_devtools)) { + componentInstance.__devtoolsApi = api; + componentInstance.__vrl_devtools.forEach(devtoolsData => { + let backgroundColor = ORANGE_400; + let tooltip = ''; + if (devtoolsData.isExactActive) { + backgroundColor = LIME_500; + tooltip = 'This is exactly active'; + } + else if (devtoolsData.isActive) { + backgroundColor = BLUE_600; + tooltip = 'This link is active'; + } + node.tags.push({ + label: devtoolsData.route.path, + textColor: 0, + tooltip, + backgroundColor, + }); + }); + } + }); + watch(router.currentRoute, () => { + // refresh active state + refreshRoutesView(); + api.notifyComponentUpdate(); + api.sendInspectorTree(routerInspectorId); + api.sendInspectorState(routerInspectorId); + }); + const navigationsLayerId = 'router:navigations:' + id; + api.addTimelineLayer({ + id: navigationsLayerId, + label: `Router${id ? ' ' + id : ''} Navigations`, + color: 0x40a8c4, + }); + // const errorsLayerId = 'router:errors' + // api.addTimelineLayer({ + // id: errorsLayerId, + // label: 'Router Errors', + // color: 0xea5455, + // }) + router.onError((error, to) => { + api.addTimelineEvent({ + layerId: navigationsLayerId, + event: { + title: 'Error during Navigation', + subtitle: to.fullPath, + logType: 'error', + time: api.now(), + data: { error }, + groupId: to.meta.__navigationId, + }, + }); + }); + // attached to `meta` and used to group events + let navigationId = 0; + router.beforeEach((to, from) => { + const data = { + guard: formatDisplay('beforeEach'), + from: formatRouteLocation(from, 'Current Location during this navigation'), + to: formatRouteLocation(to, 'Target location'), + }; + // Used to group navigations together, hide from devtools + Object.defineProperty(to.meta, '__navigationId', { + value: navigationId++, + }); + api.addTimelineEvent({ + layerId: navigationsLayerId, + event: { + time: api.now(), + title: 'Start of navigation', + subtitle: to.fullPath, + data, + groupId: to.meta.__navigationId, + }, + }); + }); + router.afterEach((to, from, failure) => { + const data = { + guard: formatDisplay('afterEach'), + }; + if (failure) { + data.failure = { + _custom: { + type: Error, + readOnly: true, + display: failure ? failure.message : '', + tooltip: 'Navigation Failure', + value: failure, + }, + }; + data.status = formatDisplay('âŒ'); + } + else { + data.status = formatDisplay('✅'); + } + // we set here to have the right order + data.from = formatRouteLocation(from, 'Current Location during this navigation'); + data.to = formatRouteLocation(to, 'Target location'); + api.addTimelineEvent({ + layerId: navigationsLayerId, + event: { + title: 'End of navigation', + subtitle: to.fullPath, + time: api.now(), + data, + logType: failure ? 'warning' : 'default', + groupId: to.meta.__navigationId, + }, + }); + }); + /** + * Inspector of Existing routes + */ + const routerInspectorId = 'router-inspector:' + id; + api.addInspector({ + id: routerInspectorId, + label: 'Routes' + (id ? ' ' + id : ''), + icon: 'book', + treeFilterPlaceholder: 'Search routes', + }); + function refreshRoutesView() { + // the routes view isn't active + if (!activeRoutesPayload) + return; + const payload = activeRoutesPayload; + // children routes will appear as nested + let routes = matcher.getRoutes().filter(route => !route.parent || + // these routes have a parent with no component which will not appear in the view + // therefore we still need to include them + !route.parent.record.components); + // reset match state to false + routes.forEach(resetMatchStateOnRouteRecord); + // apply a match state if there is a payload + if (payload.filter) { + routes = routes.filter(route => + // save matches state based on the payload + isRouteMatching(route, payload.filter.toLowerCase())); + } + // mark active routes + routes.forEach(route => markRouteRecordActive(route, router.currentRoute.value)); + payload.rootNodes = routes.map(formatRouteRecordForInspector); + } + let activeRoutesPayload; + api.on.getInspectorTree(payload => { + activeRoutesPayload = payload; + if (payload.app === app && payload.inspectorId === routerInspectorId) { + refreshRoutesView(); + } + }); + /** + * Display information about the currently selected route record + */ + api.on.getInspectorState(payload => { + if (payload.app === app && payload.inspectorId === routerInspectorId) { + const routes = matcher.getRoutes(); + const route = routes.find(route => route.record.__vd_id === payload.nodeId); + if (route) { + payload.state = { + options: formatRouteRecordMatcherForStateInspector(route), + }; + } + } + }); + api.sendInspectorTree(routerInspectorId); + api.sendInspectorState(routerInspectorId); + }); +} +function modifierForKey(key) { + if (key.optional) { + return key.repeatable ? '*' : '?'; + } + else { + return key.repeatable ? '+' : ''; + } +} +function formatRouteRecordMatcherForStateInspector(route) { + const { record } = route; + const fields = [ + { editable: false, key: 'path', value: record.path }, + ]; + if (record.name != null) { + fields.push({ + editable: false, + key: 'name', + value: record.name, + }); + } + fields.push({ editable: false, key: 'regexp', value: route.re }); + if (route.keys.length) { + fields.push({ + editable: false, + key: 'keys', + value: { + _custom: { + type: null, + readOnly: true, + display: route.keys + .map(key => `${key.name}${modifierForKey(key)}`) + .join(' '), + tooltip: 'Param keys', + value: route.keys, + }, + }, + }); + } + if (record.redirect != null) { + fields.push({ + editable: false, + key: 'redirect', + value: record.redirect, + }); + } + if (route.alias.length) { + fields.push({ + editable: false, + key: 'aliases', + value: route.alias.map(alias => alias.record.path), + }); + } + if (Object.keys(route.record.meta).length) { + fields.push({ + editable: false, + key: 'meta', + value: route.record.meta, + }); + } + fields.push({ + key: 'score', + editable: false, + value: { + _custom: { + type: null, + readOnly: true, + display: route.score.map(score => score.join(', ')).join(' | '), + tooltip: 'Score used to sort routes', + value: route.score, + }, + }, + }); + return fields; +} +/** + * Extracted from tailwind palette + */ +const PINK_500 = 0xec4899; +const BLUE_600 = 0x2563eb; +const LIME_500 = 0x84cc16; +const CYAN_400 = 0x22d3ee; +const ORANGE_400 = 0xfb923c; +// const GRAY_100 = 0xf4f4f5 +const DARK = 0x666666; +function formatRouteRecordForInspector(route) { + const tags = []; + const { record } = route; + if (record.name != null) { + tags.push({ + label: String(record.name), + textColor: 0, + backgroundColor: CYAN_400, + }); + } + if (record.aliasOf) { + tags.push({ + label: 'alias', + textColor: 0, + backgroundColor: ORANGE_400, + }); + } + if (route.__vd_match) { + tags.push({ + label: 'matches', + textColor: 0, + backgroundColor: PINK_500, + }); + } + if (route.__vd_exactActive) { + tags.push({ + label: 'exact', + textColor: 0, + backgroundColor: LIME_500, + }); + } + if (route.__vd_active) { + tags.push({ + label: 'active', + textColor: 0, + backgroundColor: BLUE_600, + }); + } + if (record.redirect) { + tags.push({ + label: typeof record.redirect === 'string' + ? `redirect: ${record.redirect}` + : 'redirects', + textColor: 0xffffff, + backgroundColor: DARK, + }); + } + // add an id to be able to select it. Using the `path` is not possible because + // empty path children would collide with their parents + let id = record.__vd_id; + if (id == null) { + id = String(routeRecordId++); + record.__vd_id = id; + } + return { + id, + label: record.path, + tags, + children: route.children.map(formatRouteRecordForInspector), + }; +} +// incremental id for route records and inspector state +let routeRecordId = 0; +const EXTRACT_REGEXP_RE = /^\/(.*)\/([a-z]*)$/; +function markRouteRecordActive(route, currentRoute) { + // no route will be active if matched is empty + // reset the matching state + const isExactActive = currentRoute.matched.length && + isSameRouteRecord(currentRoute.matched[currentRoute.matched.length - 1], route.record); + route.__vd_exactActive = route.__vd_active = isExactActive; + if (!isExactActive) { + route.__vd_active = currentRoute.matched.some(match => isSameRouteRecord(match, route.record)); + } + route.children.forEach(childRoute => markRouteRecordActive(childRoute, currentRoute)); +} +function resetMatchStateOnRouteRecord(route) { + route.__vd_match = false; + route.children.forEach(resetMatchStateOnRouteRecord); +} +function isRouteMatching(route, filter) { + const found = String(route.re).match(EXTRACT_REGEXP_RE); + route.__vd_match = false; + if (!found || found.length < 3) { + return false; + } + // use a regexp without $ at the end to match nested routes better + const nonEndingRE = new RegExp(found[1].replace(/\$$/, ''), found[2]); + if (nonEndingRE.test(filter)) { + // mark children as matches + route.children.forEach(child => isRouteMatching(child, filter)); + // exception case: `/` + if (route.record.path !== '/' || filter === '/') { + route.__vd_match = route.re.test(filter); + return true; + } + // hide the / route + return false; + } + const path = route.record.path.toLowerCase(); + const decodedPath = decode(path); + // also allow partial matching on the path + if (!filter.startsWith('/') && + (decodedPath.includes(filter) || path.includes(filter))) + return true; + if (decodedPath.startsWith(filter) || path.startsWith(filter)) + return true; + if (route.record.name && String(route.record.name).includes(filter)) + return true; + return route.children.some(child => isRouteMatching(child, filter)); +} +function omit(obj, keys) { + const ret = {}; + for (const key in obj) { + if (!keys.includes(key)) { + // @ts-expect-error + ret[key] = obj[key]; + } + } + return ret; +} + +/** + * Creates a Router instance that can be used by a Vue app. + * + * @param options - {@link RouterOptions} + */ +function createRouter(options) { + const matcher = createRouterMatcher(options.routes, options); + const parseQuery$1 = options.parseQuery || parseQuery; + const stringifyQuery$1 = options.stringifyQuery || stringifyQuery; + const routerHistory = options.history; + if (!routerHistory) + throw new Error('Provide the "history" option when calling "createRouter()":' + + ' https://next.router.vuejs.org/api/#history.'); + const beforeGuards = useCallbacks(); + const beforeResolveGuards = useCallbacks(); + const afterGuards = useCallbacks(); + const currentRoute = shallowRef(START_LOCATION_NORMALIZED); + let pendingLocation = START_LOCATION_NORMALIZED; + // leave the scrollRestoration if no scrollBehavior is provided + if (isBrowser && options.scrollBehavior && 'scrollRestoration' in history) { + history.scrollRestoration = 'manual'; + } + const normalizeParams = applyToParams.bind(null, paramValue => '' + paramValue); + const encodeParams = applyToParams.bind(null, encodeParam); + const decodeParams = + // @ts-expect-error: intentionally avoid the type check + applyToParams.bind(null, decode); + function addRoute(parentOrRoute, route) { + let parent; + let record; + if (isRouteName(parentOrRoute)) { + parent = matcher.getRecordMatcher(parentOrRoute); + record = route; + } + else { + record = parentOrRoute; + } + return matcher.addRoute(record, parent); + } + function removeRoute(name) { + const recordMatcher = matcher.getRecordMatcher(name); + if (recordMatcher) { + matcher.removeRoute(recordMatcher); + } + else { + warn(`Cannot remove non-existent route "${String(name)}"`); + } + } + function getRoutes() { + return matcher.getRoutes().map(routeMatcher => routeMatcher.record); + } + function hasRoute(name) { + return !!matcher.getRecordMatcher(name); + } + function resolve(rawLocation, currentLocation) { + // const objectLocation = routerLocationAsObject(rawLocation) + // we create a copy to modify it later + currentLocation = assign({}, currentLocation || currentRoute.value); + if (typeof rawLocation === 'string') { + const locationNormalized = parseURL(parseQuery$1, rawLocation, currentLocation.path); + const matchedRoute = matcher.resolve({ path: locationNormalized.path }, currentLocation); + const href = routerHistory.createHref(locationNormalized.fullPath); + { + if (href.startsWith('//')) + warn(`Location "${rawLocation}" resolved to "${href}". A resolved location cannot start with multiple slashes.`); + else if (!matchedRoute.matched.length) { + warn(`No match found for location with path "${rawLocation}"`); + } + } + // locationNormalized is always a new object + return assign(locationNormalized, matchedRoute, { + params: decodeParams(matchedRoute.params), + hash: decode(locationNormalized.hash), + redirectedFrom: undefined, + href, + }); + } + let matcherLocation; + // path could be relative in object as well + if ('path' in rawLocation) { + if ('params' in rawLocation && + !('name' in rawLocation) && + // @ts-expect-error: the type is never + Object.keys(rawLocation.params).length) { + warn(`Path "${rawLocation.path}" was passed with params but they will be ignored. Use a named route alongside params instead.`); + } + matcherLocation = assign({}, rawLocation, { + path: parseURL(parseQuery$1, rawLocation.path, currentLocation.path).path, + }); + } + else { + // remove any nullish param + const targetParams = assign({}, rawLocation.params); + for (const key in targetParams) { + if (targetParams[key] == null) { + delete targetParams[key]; + } + } + // pass encoded values to the matcher, so it can produce encoded path and fullPath + matcherLocation = assign({}, rawLocation, { + params: encodeParams(targetParams), + }); + // current location params are decoded, we need to encode them in case the + // matcher merges the params + currentLocation.params = encodeParams(currentLocation.params); + } + const matchedRoute = matcher.resolve(matcherLocation, currentLocation); + const hash = rawLocation.hash || ''; + if (hash && !hash.startsWith('#')) { + warn(`A \`hash\` should always start with the character "#". Replace "${hash}" with "#${hash}".`); + } + // the matcher might have merged current location params, so + // we need to run the decoding again + matchedRoute.params = normalizeParams(decodeParams(matchedRoute.params)); + const fullPath = stringifyURL(stringifyQuery$1, assign({}, rawLocation, { + hash: encodeHash(hash), + path: matchedRoute.path, + })); + const href = routerHistory.createHref(fullPath); + { + if (href.startsWith('//')) { + warn(`Location "${rawLocation}" resolved to "${href}". A resolved location cannot start with multiple slashes.`); + } + else if (!matchedRoute.matched.length) { + warn(`No match found for location with path "${'path' in rawLocation ? rawLocation.path : rawLocation}"`); + } + } + return assign({ + fullPath, + // keep the hash encoded so fullPath is effectively path + encodedQuery + + // hash + hash, + query: + // if the user is using a custom query lib like qs, we might have + // nested objects, so we keep the query as is, meaning it can contain + // numbers at `$route.query`, but at the point, the user will have to + // use their own type anyway. + // https://github.com/vuejs/router/issues/328#issuecomment-649481567 + stringifyQuery$1 === stringifyQuery + ? normalizeQuery(rawLocation.query) + : (rawLocation.query || {}), + }, matchedRoute, { + redirectedFrom: undefined, + href, + }); + } + function locationAsObject(to) { + return typeof to === 'string' + ? parseURL(parseQuery$1, to, currentRoute.value.path) + : assign({}, to); + } + function checkCanceledNavigation(to, from) { + if (pendingLocation !== to) { + return createRouterError(8 /* ErrorTypes.NAVIGATION_CANCELLED */, { + from, + to, + }); + } + } + function push(to) { + return pushWithRedirect(to); + } + function replace(to) { + return push(assign(locationAsObject(to), { replace: true })); + } + function handleRedirectRecord(to) { + const lastMatched = to.matched[to.matched.length - 1]; + if (lastMatched && lastMatched.redirect) { + const { redirect } = lastMatched; + let newTargetLocation = typeof redirect === 'function' ? redirect(to) : redirect; + if (typeof newTargetLocation === 'string') { + newTargetLocation = + newTargetLocation.includes('?') || newTargetLocation.includes('#') + ? (newTargetLocation = locationAsObject(newTargetLocation)) + : // force empty params + { path: newTargetLocation }; + // @ts-expect-error: force empty params when a string is passed to let + // the router parse them again + newTargetLocation.params = {}; + } + if (!('path' in newTargetLocation) && + !('name' in newTargetLocation)) { + warn(`Invalid redirect found:\n${JSON.stringify(newTargetLocation, null, 2)}\n when navigating to "${to.fullPath}". A redirect must contain a name or path. This will break in production.`); + throw new Error('Invalid redirect'); + } + return assign({ + query: to.query, + hash: to.hash, + // avoid transferring params if the redirect has a path + params: 'path' in newTargetLocation ? {} : to.params, + }, newTargetLocation); + } + } + function pushWithRedirect(to, redirectedFrom) { + const targetLocation = (pendingLocation = resolve(to)); + const from = currentRoute.value; + const data = to.state; + const force = to.force; + // to could be a string where `replace` is a function + const replace = to.replace === true; + const shouldRedirect = handleRedirectRecord(targetLocation); + if (shouldRedirect) + return pushWithRedirect(assign(locationAsObject(shouldRedirect), { + state: typeof shouldRedirect === 'object' + ? assign({}, data, shouldRedirect.state) + : data, + force, + replace, + }), + // keep original redirectedFrom if it exists + redirectedFrom || targetLocation); + // if it was a redirect we already called `pushWithRedirect` above + const toLocation = targetLocation; + toLocation.redirectedFrom = redirectedFrom; + let failure; + if (!force && isSameRouteLocation(stringifyQuery$1, from, targetLocation)) { + failure = createRouterError(16 /* ErrorTypes.NAVIGATION_DUPLICATED */, { to: toLocation, from }); + // trigger scroll to allow scrolling to the same anchor + handleScroll(from, from, + // this is a push, the only way for it to be triggered from a + // history.listen is with a redirect, which makes it become a push + true, + // This cannot be the first navigation because the initial location + // cannot be manually navigated to + false); + } + return (failure ? Promise.resolve(failure) : navigate(toLocation, from)) + .catch((error) => isNavigationFailure(error) + ? // navigation redirects still mark the router as ready + isNavigationFailure(error, 2 /* ErrorTypes.NAVIGATION_GUARD_REDIRECT */) + ? error + : markAsReady(error) // also returns the error + : // reject any unknown error + triggerError(error, toLocation, from)) + .then((failure) => { + if (failure) { + if (isNavigationFailure(failure, 2 /* ErrorTypes.NAVIGATION_GUARD_REDIRECT */)) { + if (// we are redirecting to the same location we were already at + isSameRouteLocation(stringifyQuery$1, resolve(failure.to), toLocation) && + // and we have done it a couple of times + redirectedFrom && + // @ts-expect-error: added only in dev + (redirectedFrom._count = redirectedFrom._count + ? // @ts-expect-error + redirectedFrom._count + 1 + : 1) > 30) { + warn(`Detected a possibly infinite redirection in a navigation guard when going from "${from.fullPath}" to "${toLocation.fullPath}". Aborting to avoid a Stack Overflow.\n Are you always returning a new location within a navigation guard? That would lead to this error. Only return when redirecting or aborting, that should fix this. This might break in production if not fixed.`); + return Promise.reject(new Error('Infinite redirect in navigation guard')); + } + return pushWithRedirect( + // keep options + assign({ + // preserve an existing replacement but allow the redirect to override it + replace, + }, locationAsObject(failure.to), { + state: typeof failure.to === 'object' + ? assign({}, data, failure.to.state) + : data, + force, + }), + // preserve the original redirectedFrom if any + redirectedFrom || toLocation); + } + } + else { + // if we fail we don't finalize the navigation + failure = finalizeNavigation(toLocation, from, true, replace, data); + } + triggerAfterEach(toLocation, from, failure); + return failure; + }); + } + /** + * Helper to reject and skip all navigation guards if a new navigation happened + * @param to + * @param from + */ + function checkCanceledNavigationAndReject(to, from) { + const error = checkCanceledNavigation(to, from); + return error ? Promise.reject(error) : Promise.resolve(); + } + function runWithContext(fn) { + const app = installedApps.values().next().value; + // support Vue < 3.3 + return app && typeof app.runWithContext === 'function' + ? app.runWithContext(fn) + : fn(); + } + // TODO: refactor the whole before guards by internally using router.beforeEach + function navigate(to, from) { + let guards; + const [leavingRecords, updatingRecords, enteringRecords] = extractChangingRecords(to, from); + // all components here have been resolved once because we are leaving + guards = extractComponentsGuards(leavingRecords.reverse(), 'beforeRouteLeave', to, from); + // leavingRecords is already reversed + for (const record of leavingRecords) { + record.leaveGuards.forEach(guard => { + guards.push(guardToPromiseFn(guard, to, from)); + }); + } + const canceledNavigationCheck = checkCanceledNavigationAndReject.bind(null, to, from); + guards.push(canceledNavigationCheck); + // run the queue of per route beforeRouteLeave guards + return (runGuardQueue(guards) + .then(() => { + // check global guards beforeEach + guards = []; + for (const guard of beforeGuards.list()) { + guards.push(guardToPromiseFn(guard, to, from)); + } + guards.push(canceledNavigationCheck); + return runGuardQueue(guards); + }) + .then(() => { + // check in components beforeRouteUpdate + guards = extractComponentsGuards(updatingRecords, 'beforeRouteUpdate', to, from); + for (const record of updatingRecords) { + record.updateGuards.forEach(guard => { + guards.push(guardToPromiseFn(guard, to, from)); + }); + } + guards.push(canceledNavigationCheck); + // run the queue of per route beforeEnter guards + return runGuardQueue(guards); + }) + .then(() => { + // check the route beforeEnter + guards = []; + for (const record of enteringRecords) { + // do not trigger beforeEnter on reused views + if (record.beforeEnter) { + if (isArray(record.beforeEnter)) { + for (const beforeEnter of record.beforeEnter) + guards.push(guardToPromiseFn(beforeEnter, to, from)); + } + else { + guards.push(guardToPromiseFn(record.beforeEnter, to, from)); + } + } + } + guards.push(canceledNavigationCheck); + // run the queue of per route beforeEnter guards + return runGuardQueue(guards); + }) + .then(() => { + // NOTE: at this point to.matched is normalized and does not contain any () => Promise + // clear existing enterCallbacks, these are added by extractComponentsGuards + to.matched.forEach(record => (record.enterCallbacks = {})); + // check in-component beforeRouteEnter + guards = extractComponentsGuards(enteringRecords, 'beforeRouteEnter', to, from); + guards.push(canceledNavigationCheck); + // run the queue of per route beforeEnter guards + return runGuardQueue(guards); + }) + .then(() => { + // check global guards beforeResolve + guards = []; + for (const guard of beforeResolveGuards.list()) { + guards.push(guardToPromiseFn(guard, to, from)); + } + guards.push(canceledNavigationCheck); + return runGuardQueue(guards); + }) + // catch any navigation canceled + .catch(err => isNavigationFailure(err, 8 /* ErrorTypes.NAVIGATION_CANCELLED */) + ? err + : Promise.reject(err))); + } + function triggerAfterEach(to, from, failure) { + // navigation is confirmed, call afterGuards + // TODO: wrap with error handlers + afterGuards + .list() + .forEach(guard => runWithContext(() => guard(to, from, failure))); + } + /** + * - Cleans up any navigation guards + * - Changes the url if necessary + * - Calls the scrollBehavior + */ + function finalizeNavigation(toLocation, from, isPush, replace, data) { + // a more recent navigation took place + const error = checkCanceledNavigation(toLocation, from); + if (error) + return error; + // only consider as push if it's not the first navigation + const isFirstNavigation = from === START_LOCATION_NORMALIZED; + const state = !isBrowser ? {} : history.state; + // change URL only if the user did a push/replace and if it's not the initial navigation because + // it's just reflecting the url + if (isPush) { + // on the initial navigation, we want to reuse the scroll position from + // history state if it exists + if (replace || isFirstNavigation) + routerHistory.replace(toLocation.fullPath, assign({ + scroll: isFirstNavigation && state && state.scroll, + }, data)); + else + routerHistory.push(toLocation.fullPath, data); + } + // accept current navigation + currentRoute.value = toLocation; + handleScroll(toLocation, from, isPush, isFirstNavigation); + markAsReady(); + } + let removeHistoryListener; + // attach listener to history to trigger navigations + function setupListeners() { + // avoid setting up listeners twice due to an invalid first navigation + if (removeHistoryListener) + return; + removeHistoryListener = routerHistory.listen((to, _from, info) => { + if (!router.listening) + return; + // cannot be a redirect route because it was in history + const toLocation = resolve(to); + // due to dynamic routing, and to hash history with manual navigation + // (manually changing the url or calling history.hash = '#/somewhere'), + // there could be a redirect record in history + const shouldRedirect = handleRedirectRecord(toLocation); + if (shouldRedirect) { + pushWithRedirect(assign(shouldRedirect, { replace: true }), toLocation).catch(noop); + return; + } + pendingLocation = toLocation; + const from = currentRoute.value; + // TODO: should be moved to web history? + if (isBrowser) { + saveScrollPosition(getScrollKey(from.fullPath, info.delta), computeScrollPosition()); + } + navigate(toLocation, from) + .catch((error) => { + if (isNavigationFailure(error, 4 /* ErrorTypes.NAVIGATION_ABORTED */ | 8 /* ErrorTypes.NAVIGATION_CANCELLED */)) { + return error; + } + if (isNavigationFailure(error, 2 /* ErrorTypes.NAVIGATION_GUARD_REDIRECT */)) { + // Here we could call if (info.delta) routerHistory.go(-info.delta, + // false) but this is bug prone as we have no way to wait the + // navigation to be finished before calling pushWithRedirect. Using + // a setTimeout of 16ms seems to work but there is no guarantee for + // it to work on every browser. So instead we do not restore the + // history entry and trigger a new navigation as requested by the + // navigation guard. + // the error is already handled by router.push we just want to avoid + // logging the error + pushWithRedirect(error.to, toLocation + // avoid an uncaught rejection, let push call triggerError + ) + .then(failure => { + // manual change in hash history #916 ending up in the URL not + // changing, but it was changed by the manual url change, so we + // need to manually change it ourselves + if (isNavigationFailure(failure, 4 /* ErrorTypes.NAVIGATION_ABORTED */ | + 16 /* ErrorTypes.NAVIGATION_DUPLICATED */) && + !info.delta && + info.type === NavigationType.pop) { + routerHistory.go(-1, false); + } + }) + .catch(noop); + // avoid the then branch + return Promise.reject(); + } + // do not restore history on unknown direction + if (info.delta) { + routerHistory.go(-info.delta, false); + } + // unrecognized error, transfer to the global handler + return triggerError(error, toLocation, from); + }) + .then((failure) => { + failure = + failure || + finalizeNavigation( + // after navigation, all matched components are resolved + toLocation, from, false); + // revert the navigation + if (failure) { + if (info.delta && + // a new navigation has been triggered, so we do not want to revert, that will change the current history + // entry while a different route is displayed + !isNavigationFailure(failure, 8 /* ErrorTypes.NAVIGATION_CANCELLED */)) { + routerHistory.go(-info.delta, false); + } + else if (info.type === NavigationType.pop && + isNavigationFailure(failure, 4 /* ErrorTypes.NAVIGATION_ABORTED */ | 16 /* ErrorTypes.NAVIGATION_DUPLICATED */)) { + // manual change in hash history #916 + // it's like a push but lacks the information of the direction + routerHistory.go(-1, false); + } + } + triggerAfterEach(toLocation, from, failure); + }) + // avoid warnings in the console about uncaught rejections, they are logged by triggerErrors + .catch(noop); + }); + } + // Initialization and Errors + let readyHandlers = useCallbacks(); + let errorListeners = useCallbacks(); + let ready; + /** + * Trigger errorListeners added via onError and throws the error as well + * + * @param error - error to throw + * @param to - location we were navigating to when the error happened + * @param from - location we were navigating from when the error happened + * @returns the error as a rejected promise + */ + function triggerError(error, to, from) { + markAsReady(error); + const list = errorListeners.list(); + if (list.length) { + list.forEach(handler => handler(error, to, from)); + } + else { + { + warn('uncaught error during route navigation:'); + } + console.error(error); + } + // reject the error no matter there were error listeners or not + return Promise.reject(error); + } + function isReady() { + if (ready && currentRoute.value !== START_LOCATION_NORMALIZED) + return Promise.resolve(); + return new Promise((resolve, reject) => { + readyHandlers.add([resolve, reject]); + }); + } + function markAsReady(err) { + if (!ready) { + // still not ready if an error happened + ready = !err; + setupListeners(); + readyHandlers + .list() + .forEach(([resolve, reject]) => (err ? reject(err) : resolve())); + readyHandlers.reset(); + } + return err; + } + // Scroll behavior + function handleScroll(to, from, isPush, isFirstNavigation) { + const { scrollBehavior } = options; + if (!isBrowser || !scrollBehavior) + return Promise.resolve(); + const scrollPosition = (!isPush && getSavedScrollPosition(getScrollKey(to.fullPath, 0))) || + ((isFirstNavigation || !isPush) && + history.state && + history.state.scroll) || + null; + return nextTick() + .then(() => scrollBehavior(to, from, scrollPosition)) + .then(position => position && scrollToPosition(position)) + .catch(err => triggerError(err, to, from)); + } + const go = (delta) => routerHistory.go(delta); + let started; + const installedApps = new Set(); + const router = { + currentRoute, + listening: true, + addRoute, + removeRoute, + hasRoute, + getRoutes, + resolve, + options, + push, + replace, + go, + back: () => go(-1), + forward: () => go(1), + beforeEach: beforeGuards.add, + beforeResolve: beforeResolveGuards.add, + afterEach: afterGuards.add, + onError: errorListeners.add, + isReady, + install(app) { + const router = this; + app.component('RouterLink', RouterLink); + app.component('RouterView', RouterView); + app.config.globalProperties.$router = router; + Object.defineProperty(app.config.globalProperties, '$route', { + enumerable: true, + get: () => unref(currentRoute), + }); + // this initial navigation is only necessary on client, on server it doesn't + // make sense because it will create an extra unnecessary navigation and could + // lead to problems + if (isBrowser && + // used for the initial navigation client side to avoid pushing + // multiple times when the router is used in multiple apps + !started && + currentRoute.value === START_LOCATION_NORMALIZED) { + // see above + started = true; + push(routerHistory.location).catch(err => { + warn('Unexpected error when starting the router:', err); + }); + } + const reactiveRoute = {}; + for (const key in START_LOCATION_NORMALIZED) { + Object.defineProperty(reactiveRoute, key, { + get: () => currentRoute.value[key], + enumerable: true, + }); + } + app.provide(routerKey, router); + app.provide(routeLocationKey, shallowReactive(reactiveRoute)); + app.provide(routerViewLocationKey, currentRoute); + const unmountApp = app.unmount; + installedApps.add(app); + app.unmount = function () { + installedApps.delete(app); + // the router is not attached to an app anymore + if (installedApps.size < 1) { + // invalidate the current navigation + pendingLocation = START_LOCATION_NORMALIZED; + removeHistoryListener && removeHistoryListener(); + removeHistoryListener = null; + currentRoute.value = START_LOCATION_NORMALIZED; + started = false; + ready = false; + } + unmountApp(); + }; + // TODO: this probably needs to be updated so it can be used by vue-termui + if (isBrowser) { + addDevtools(app, router, matcher); + } + }, + }; + // TODO: type this as NavigationGuardReturn or similar instead of any + function runGuardQueue(guards) { + return guards.reduce((promise, guard) => promise.then(() => runWithContext(guard)), Promise.resolve()); + } + return router; +} +function extractChangingRecords(to, from) { + const leavingRecords = []; + const updatingRecords = []; + const enteringRecords = []; + const len = Math.max(from.matched.length, to.matched.length); + for (let i = 0; i < len; i++) { + const recordFrom = from.matched[i]; + if (recordFrom) { + if (to.matched.find(record => isSameRouteRecord(record, recordFrom))) + updatingRecords.push(recordFrom); + else + leavingRecords.push(recordFrom); + } + const recordTo = to.matched[i]; + if (recordTo) { + // the type doesn't matter because we are comparing per reference + if (!from.matched.find(record => isSameRouteRecord(record, recordTo))) { + enteringRecords.push(recordTo); + } + } + } + return [leavingRecords, updatingRecords, enteringRecords]; +} + +/** + * Returns the router instance. Equivalent to using `$router` inside + * templates. + */ +function useRouter() { + return inject(routerKey); +} +/** + * Returns the current route location. Equivalent to using `$route` inside + * templates. + */ +function useRoute() { + return inject(routeLocationKey); +} + +export { NavigationFailureType, RouterLink, RouterView, START_LOCATION_NORMALIZED as START_LOCATION, createMemoryHistory, createRouter, createRouterMatcher, createWebHashHistory, createWebHistory, isNavigationFailure, loadRouteLocation, matchedRouteKey, onBeforeRouteLeave, onBeforeRouteUpdate, parseQuery, routeLocationKey, routerKey, routerViewLocationKey, stringifyQuery, useLink, useRoute, useRouter, viewDepthKey }; \ No newline at end of file diff --git a/hal-core/resources/web/js/vue/vue-router.esm-browser.prod.js b/hal-core/resources/web/js/vue/vue-router.esm-browser.prod.js new file mode 100644 index 00000000..64c8126c --- /dev/null +++ b/hal-core/resources/web/js/vue/vue-router.esm-browser.prod.js @@ -0,0 +1,3615 @@ +/*! + * vue-router v4.2.5 + * (c) 2023 Eduardo San Martin Morote + * @license MIT + */ +import { getCurrentInstance, inject, onUnmounted, onDeactivated, onActivated, computed, unref, watchEffect, defineComponent, reactive, h, provide, ref, watch, shallowRef, shallowReactive, nextTick } from 'vue'; +import { setupDevtoolsPlugin } from '@vue/devtools-api'; + +const isBrowser = typeof window !== 'undefined'; + +function isESModule(obj) { + return obj.__esModule || obj[Symbol.toStringTag] === 'Module'; +} +const assign = Object.assign; +function applyToParams(fn, params) { + const newParams = {}; + for (const key in params) { + const value = params[key]; + newParams[key] = isArray(value) + ? value.map(fn) + : fn(value); + } + return newParams; +} +const noop = () => { }; +/** + * Typesafe alternative to Array.isArray + * https://github.com/microsoft/TypeScript/pull/48228 + */ +const isArray = Array.isArray; + +function warn(msg) { + // avoid using ...args as it breaks in older Edge builds + const args = Array.from(arguments).slice(1); + console.warn.apply(console, ['[Vue Router warn]: ' + msg].concat(args)); +} + +const TRAILING_SLASH_RE = /\/$/; +const removeTrailingSlash = (path) => path.replace(TRAILING_SLASH_RE, ''); +/** + * Transforms a URI into a normalized history location + * + * @param parseQuery + * @param location - URI to normalize + * @param currentLocation - current absolute location. Allows resolving relative + * paths. Must start with `/`. Defaults to `/` + * @returns a normalized history location + */ +function parseURL(parseQuery, location, currentLocation = '/') { + let path, query = {}, searchString = '', hash = ''; + // Could use URL and URLSearchParams but IE 11 doesn't support it + // TODO: move to new URL() + const hashPos = location.indexOf('#'); + let searchPos = location.indexOf('?'); + // the hash appears before the search, so it's not part of the search string + if (hashPos < searchPos && hashPos >= 0) { + searchPos = -1; + } + if (searchPos > -1) { + path = location.slice(0, searchPos); + searchString = location.slice(searchPos + 1, hashPos > -1 ? hashPos : location.length); + query = parseQuery(searchString); + } + if (hashPos > -1) { + path = path || location.slice(0, hashPos); + // keep the # character + hash = location.slice(hashPos, location.length); + } + // no search and no query + path = resolveRelativePath(path != null ? path : location, currentLocation); + // empty path means a relative query or hash `?foo=f`, `#thing` + return { + fullPath: path + (searchString && '?') + searchString + hash, + path, + query, + hash, + }; +} +/** + * Stringifies a URL object + * + * @param stringifyQuery + * @param location + */ +function stringifyURL(stringifyQuery, location) { + const query = location.query ? stringifyQuery(location.query) : ''; + return location.path + (query && '?') + query + (location.hash || ''); +} +/** + * Strips off the base from the beginning of a location.pathname in a non-case-sensitive way. + * + * @param pathname - location.pathname + * @param base - base to strip off + */ +function stripBase(pathname, base) { + // no base or base is not found at the beginning + if (!base || !pathname.toLowerCase().startsWith(base.toLowerCase())) + return pathname; + return pathname.slice(base.length) || '/'; +} +/** + * Checks if two RouteLocation are equal. This means that both locations are + * pointing towards the same {@link RouteRecord} and that all `params`, `query` + * parameters and `hash` are the same + * + * @param stringifyQuery - A function that takes a query object of type LocationQueryRaw and returns a string representation of it. + * @param a - first {@link RouteLocation} + * @param b - second {@link RouteLocation} + */ +function isSameRouteLocation(stringifyQuery, a, b) { + const aLastIndex = a.matched.length - 1; + const bLastIndex = b.matched.length - 1; + return (aLastIndex > -1 && + aLastIndex === bLastIndex && + isSameRouteRecord(a.matched[aLastIndex], b.matched[bLastIndex]) && + isSameRouteLocationParams(a.params, b.params) && + stringifyQuery(a.query) === stringifyQuery(b.query) && + a.hash === b.hash); +} +/** + * Check if two `RouteRecords` are equal. Takes into account aliases: they are + * considered equal to the `RouteRecord` they are aliasing. + * + * @param a - first {@link RouteRecord} + * @param b - second {@link RouteRecord} + */ +function isSameRouteRecord(a, b) { + // since the original record has an undefined value for aliasOf + // but all aliases point to the original record, this will always compare + // the original record + return (a.aliasOf || a) === (b.aliasOf || b); +} +function isSameRouteLocationParams(a, b) { + if (Object.keys(a).length !== Object.keys(b).length) + return false; + for (const key in a) { + if (!isSameRouteLocationParamsValue(a[key], b[key])) + return false; + } + return true; +} +function isSameRouteLocationParamsValue(a, b) { + return isArray(a) + ? isEquivalentArray(a, b) + : isArray(b) + ? isEquivalentArray(b, a) + : a === b; +} +/** + * Check if two arrays are the same or if an array with one single entry is the + * same as another primitive value. Used to check query and parameters + * + * @param a - array of values + * @param b - array of values or a single value + */ +function isEquivalentArray(a, b) { + return isArray(b) + ? a.length === b.length && a.every((value, i) => value === b[i]) + : a.length === 1 && a[0] === b; +} +/** + * Resolves a relative path that starts with `.`. + * + * @param to - path location we are resolving + * @param from - currentLocation.path, should start with `/` + */ +function resolveRelativePath(to, from) { + if (to.startsWith('/')) + return to; + if (!from.startsWith('/')) { + warn(`Cannot resolve a relative location without an absolute path. Trying to resolve "${to}" from "${from}". It should look like "/${from}".`); + return to; + } + if (!to) + return from; + const fromSegments = from.split('/'); + const toSegments = to.split('/'); + const lastToSegment = toSegments[toSegments.length - 1]; + // make . and ./ the same (../ === .., ../../ === ../..) + // this is the same behavior as new URL() + if (lastToSegment === '..' || lastToSegment === '.') { + toSegments.push(''); + } + let position = fromSegments.length - 1; + let toPosition; + let segment; + for (toPosition = 0; toPosition < toSegments.length; toPosition++) { + segment = toSegments[toPosition]; + // we stay on the same position + if (segment === '.') + continue; + // go up in the from array + if (segment === '..') { + // we can't go below zero, but we still need to increment toPosition + if (position > 1) + position--; + // continue + } + // we reached a non-relative path, we stop here + else + break; + } + return (fromSegments.slice(0, position).join('/') + + '/' + + toSegments + // ensure we use at least the last element in the toSegments + .slice(toPosition - (toPosition === toSegments.length ? 1 : 0)) + .join('/')); +} + +var NavigationType; +(function (NavigationType) { + NavigationType["pop"] = "pop"; + NavigationType["push"] = "push"; +})(NavigationType || (NavigationType = {})); +var NavigationDirection; +(function (NavigationDirection) { + NavigationDirection["back"] = "back"; + NavigationDirection["forward"] = "forward"; + NavigationDirection["unknown"] = ""; +})(NavigationDirection || (NavigationDirection = {})); +/** + * Starting location for Histories + */ +const START = ''; +// Generic utils +/** + * Normalizes a base by removing any trailing slash and reading the base tag if + * present. + * + * @param base - base to normalize + */ +function normalizeBase(base) { + if (!base) { + if (isBrowser) { + // respect tag + const baseEl = document.querySelector('base'); + base = (baseEl && baseEl.getAttribute('href')) || '/'; + // strip full URL origin + base = base.replace(/^\w+:\/\/[^\/]+/, ''); + } + else { + base = '/'; + } + } + // ensure leading slash when it was removed by the regex above avoid leading + // slash with hash because the file could be read from the disk like file:// + // and the leading slash would cause problems + if (base[0] !== '/' && base[0] !== '#') + base = '/' + base; + // remove the trailing slash so all other method can just do `base + fullPath` + // to build an href + return removeTrailingSlash(base); +} +// remove any character before the hash +const BEFORE_HASH_RE = /^[^#]+#/; +function createHref(base, location) { + return base.replace(BEFORE_HASH_RE, '#') + location; +} + +function getElementPosition(el, offset) { + const docRect = document.documentElement.getBoundingClientRect(); + const elRect = el.getBoundingClientRect(); + return { + behavior: offset.behavior, + left: elRect.left - docRect.left - (offset.left || 0), + top: elRect.top - docRect.top - (offset.top || 0), + }; +} +const computeScrollPosition = () => ({ + left: window.pageXOffset, + top: window.pageYOffset, +}); +function scrollToPosition(position) { + let scrollToOptions; + if ('el' in position) { + const positionEl = position.el; + const isIdSelector = typeof positionEl === 'string' && positionEl.startsWith('#'); + /** + * `id`s can accept pretty much any characters, including CSS combinators + * like `>` or `~`. It's still possible to retrieve elements using + * `document.getElementById('~')` but it needs to be escaped when using + * `document.querySelector('#\\~')` for it to be valid. The only + * requirements for `id`s are them to be unique on the page and to not be + * empty (`id=""`). Because of that, when passing an id selector, it should + * be properly escaped for it to work with `querySelector`. We could check + * for the id selector to be simple (no CSS combinators `+ >~`) but that + * would make things inconsistent since they are valid characters for an + * `id` but would need to be escaped when using `querySelector`, breaking + * their usage and ending up in no selector returned. Selectors need to be + * escaped: + * + * - `#1-thing` becomes `#\31 -thing` + * - `#with~symbols` becomes `#with\\~symbols` + * + * - More information about the topic can be found at + * https://mathiasbynens.be/notes/html5-id-class. + * - Practical example: https://mathiasbynens.be/demo/html5-id + */ + if (typeof position.el === 'string') { + if (!isIdSelector || !document.getElementById(position.el.slice(1))) { + try { + const foundEl = document.querySelector(position.el); + if (isIdSelector && foundEl) { + warn(`The selector "${position.el}" should be passed as "el: document.querySelector('${position.el}')" because it starts with "#".`); + // return to avoid other warnings + return; + } + } + catch (err) { + warn(`The selector "${position.el}" is invalid. If you are using an id selector, make sure to escape it. You can find more information about escaping characters in selectors at https://mathiasbynens.be/notes/css-escapes or use CSS.escape (https://developer.mozilla.org/en-US/docs/Web/API/CSS/escape).`); + // return to avoid other warnings + return; + } + } + } + const el = typeof positionEl === 'string' + ? isIdSelector + ? document.getElementById(positionEl.slice(1)) + : document.querySelector(positionEl) + : positionEl; + if (!el) { + warn(`Couldn't find element using selector "${position.el}" returned by scrollBehavior.`); + return; + } + scrollToOptions = getElementPosition(el, position); + } + else { + scrollToOptions = position; + } + if ('scrollBehavior' in document.documentElement.style) + window.scrollTo(scrollToOptions); + else { + window.scrollTo(scrollToOptions.left != null ? scrollToOptions.left : window.pageXOffset, scrollToOptions.top != null ? scrollToOptions.top : window.pageYOffset); + } +} +function getScrollKey(path, delta) { + const position = history.state ? history.state.position - delta : -1; + return position + path; +} +const scrollPositions = new Map(); +function saveScrollPosition(key, scrollPosition) { + scrollPositions.set(key, scrollPosition); +} +function getSavedScrollPosition(key) { + const scroll = scrollPositions.get(key); + // consume it so it's not used again + scrollPositions.delete(key); + return scroll; +} +// TODO: RFC about how to save scroll position +/** + * ScrollBehavior instance used by the router to compute and restore the scroll + * position when navigating. + */ +// export interface ScrollHandler { +// // returns a scroll position that can be saved in history +// compute(): ScrollPositionEntry +// // can take an extended ScrollPositionEntry +// scroll(position: ScrollPosition): void +// } +// export const scrollHandler: ScrollHandler = { +// compute: computeScroll, +// scroll: scrollToPosition, +// } + +let createBaseLocation = () => location.protocol + '//' + location.host; +/** + * Creates a normalized history location from a window.location object + * @param base - The base path + * @param location - The window.location object + */ +function createCurrentLocation(base, location) { + const { pathname, search, hash } = location; + // allows hash bases like #, /#, #/, #!, #!/, /#!/, or even /folder#end + const hashPos = base.indexOf('#'); + if (hashPos > -1) { + let slicePos = hash.includes(base.slice(hashPos)) + ? base.slice(hashPos).length + : 1; + let pathFromHash = hash.slice(slicePos); + // prepend the starting slash to hash so the url starts with /# + if (pathFromHash[0] !== '/') + pathFromHash = '/' + pathFromHash; + return stripBase(pathFromHash, ''); + } + const path = stripBase(pathname, base); + return path + search + hash; +} +function useHistoryListeners(base, historyState, currentLocation, replace) { + let listeners = []; + let teardowns = []; + // TODO: should it be a stack? a Dict. Check if the popstate listener + // can trigger twice + let pauseState = null; + const popStateHandler = ({ state, }) => { + const to = createCurrentLocation(base, location); + const from = currentLocation.value; + const fromState = historyState.value; + let delta = 0; + if (state) { + currentLocation.value = to; + historyState.value = state; + // ignore the popstate and reset the pauseState + if (pauseState && pauseState === from) { + pauseState = null; + return; + } + delta = fromState ? state.position - fromState.position : 0; + } + else { + replace(to); + } + // Here we could also revert the navigation by calling history.go(-delta) + // this listener will have to be adapted to not trigger again and to wait for the url + // to be updated before triggering the listeners. Some kind of validation function would also + // need to be passed to the listeners so the navigation can be accepted + // call all listeners + listeners.forEach(listener => { + listener(currentLocation.value, from, { + delta, + type: NavigationType.pop, + direction: delta + ? delta > 0 + ? NavigationDirection.forward + : NavigationDirection.back + : NavigationDirection.unknown, + }); + }); + }; + function pauseListeners() { + pauseState = currentLocation.value; + } + function listen(callback) { + // set up the listener and prepare teardown callbacks + listeners.push(callback); + const teardown = () => { + const index = listeners.indexOf(callback); + if (index > -1) + listeners.splice(index, 1); + }; + teardowns.push(teardown); + return teardown; + } + function beforeUnloadListener() { + const { history } = window; + if (!history.state) + return; + history.replaceState(assign({}, history.state, { scroll: computeScrollPosition() }), ''); + } + function destroy() { + for (const teardown of teardowns) + teardown(); + teardowns = []; + window.removeEventListener('popstate', popStateHandler); + window.removeEventListener('beforeunload', beforeUnloadListener); + } + // set up the listeners and prepare teardown callbacks + window.addEventListener('popstate', popStateHandler); + // TODO: could we use 'pagehide' or 'visibilitychange' instead? + // https://developer.chrome.com/blog/page-lifecycle-api/ + window.addEventListener('beforeunload', beforeUnloadListener, { + passive: true, + }); + return { + pauseListeners, + listen, + destroy, + }; +} +/** + * Creates a state object + */ +function buildState(back, current, forward, replaced = false, computeScroll = false) { + return { + back, + current, + forward, + replaced, + position: window.history.length, + scroll: computeScroll ? computeScrollPosition() : null, + }; +} +function useHistoryStateNavigation(base) { + const { history, location } = window; + // private variables + const currentLocation = { + value: createCurrentLocation(base, location), + }; + const historyState = { value: history.state }; + // build current history entry as this is a fresh navigation + if (!historyState.value) { + changeLocation(currentLocation.value, { + back: null, + current: currentLocation.value, + forward: null, + // the length is off by one, we need to decrease it + position: history.length - 1, + replaced: true, + // don't add a scroll as the user may have an anchor, and we want + // scrollBehavior to be triggered without a saved position + scroll: null, + }, true); + } + function changeLocation(to, state, replace) { + /** + * if a base tag is provided, and we are on a normal domain, we have to + * respect the provided `base` attribute because pushState() will use it and + * potentially erase anything before the `#` like at + * https://github.com/vuejs/router/issues/685 where a base of + * `/folder/#` but a base of `/` would erase the `/folder/` section. If + * there is no host, the `` tag makes no sense and if there isn't a + * base tag we can just use everything after the `#`. + */ + const hashIndex = base.indexOf('#'); + const url = hashIndex > -1 + ? (location.host && document.querySelector('base') + ? base + : base.slice(hashIndex)) + to + : createBaseLocation() + base + to; + try { + // BROWSER QUIRK + // NOTE: Safari throws a SecurityError when calling this function 100 times in 30 seconds + history[replace ? 'replaceState' : 'pushState'](state, '', url); + historyState.value = state; + } + catch (err) { + { + warn('Error with push/replace State', err); + } + // Force the navigation, this also resets the call count + location[replace ? 'replace' : 'assign'](url); + } + } + function replace(to, data) { + const state = assign({}, history.state, buildState(historyState.value.back, + // keep back and forward entries but override current position + to, historyState.value.forward, true), data, { position: historyState.value.position }); + changeLocation(to, state, true); + currentLocation.value = to; + } + function push(to, data) { + // Add to current entry the information of where we are going + // as well as saving the current position + const currentState = assign({}, + // use current history state to gracefully handle a wrong call to + // history.replaceState + // https://github.com/vuejs/router/issues/366 + historyState.value, history.state, { + forward: to, + scroll: computeScrollPosition(), + }); + if (!history.state) { + warn(`history.state seems to have been manually replaced without preserving the necessary values. Make sure to preserve existing history state if you are manually calling history.replaceState:\n\n` + + `history.replaceState(history.state, '', url)\n\n` + + `You can find more information at https://next.router.vuejs.org/guide/migration/#usage-of-history-state.`); + } + changeLocation(currentState.current, currentState, true); + const state = assign({}, buildState(currentLocation.value, to, null), { position: currentState.position + 1 }, data); + changeLocation(to, state, false); + currentLocation.value = to; + } + return { + location: currentLocation, + state: historyState, + push, + replace, + }; +} +/** + * Creates an HTML5 history. Most common history for single page applications. + * + * @param base - + */ +function createWebHistory(base) { + base = normalizeBase(base); + const historyNavigation = useHistoryStateNavigation(base); + const historyListeners = useHistoryListeners(base, historyNavigation.state, historyNavigation.location, historyNavigation.replace); + function go(delta, triggerListeners = true) { + if (!triggerListeners) + historyListeners.pauseListeners(); + history.go(delta); + } + const routerHistory = assign({ + // it's overridden right after + location: '', + base, + go, + createHref: createHref.bind(null, base), + }, historyNavigation, historyListeners); + Object.defineProperty(routerHistory, 'location', { + enumerable: true, + get: () => historyNavigation.location.value, + }); + Object.defineProperty(routerHistory, 'state', { + enumerable: true, + get: () => historyNavigation.state.value, + }); + return routerHistory; +} + +/** + * Creates an in-memory based history. The main purpose of this history is to handle SSR. It starts in a special location that is nowhere. + * It's up to the user to replace that location with the starter location by either calling `router.push` or `router.replace`. + * + * @param base - Base applied to all urls, defaults to '/' + * @returns a history object that can be passed to the router constructor + */ +function createMemoryHistory(base = '') { + let listeners = []; + let queue = [START]; + let position = 0; + base = normalizeBase(base); + function setLocation(location) { + position++; + if (position !== queue.length) { + // we are in the middle, we remove everything from here in the queue + queue.splice(position); + } + queue.push(location); + } + function triggerListeners(to, from, { direction, delta }) { + const info = { + direction, + delta, + type: NavigationType.pop, + }; + for (const callback of listeners) { + callback(to, from, info); + } + } + const routerHistory = { + // rewritten by Object.defineProperty + location: START, + // TODO: should be kept in queue + state: {}, + base, + createHref: createHref.bind(null, base), + replace(to) { + // remove current entry and decrement position + queue.splice(position--, 1); + setLocation(to); + }, + push(to, data) { + setLocation(to); + }, + listen(callback) { + listeners.push(callback); + return () => { + const index = listeners.indexOf(callback); + if (index > -1) + listeners.splice(index, 1); + }; + }, + destroy() { + listeners = []; + queue = [START]; + position = 0; + }, + go(delta, shouldTrigger = true) { + const from = this.location; + const direction = + // we are considering delta === 0 going forward, but in abstract mode + // using 0 for the delta doesn't make sense like it does in html5 where + // it reloads the page + delta < 0 ? NavigationDirection.back : NavigationDirection.forward; + position = Math.max(0, Math.min(position + delta, queue.length - 1)); + if (shouldTrigger) { + triggerListeners(this.location, from, { + direction, + delta, + }); + } + }, + }; + Object.defineProperty(routerHistory, 'location', { + enumerable: true, + get: () => queue[position], + }); + return routerHistory; +} + +/** + * Creates a hash history. Useful for web applications with no host (e.g. `file://`) or when configuring a server to + * handle any URL is not possible. + * + * @param base - optional base to provide. Defaults to `location.pathname + location.search` If there is a `` tag + * in the `head`, its value will be ignored in favor of this parameter **but note it affects all the history.pushState() + * calls**, meaning that if you use a `` tag, it's `href` value **has to match this parameter** (ignoring anything + * after the `#`). + * + * @example + * ```js + * // at https://example.com/folder + * createWebHashHistory() // gives a url of `https://example.com/folder#` + * createWebHashHistory('/folder/') // gives a url of `https://example.com/folder/#` + * // if the `#` is provided in the base, it won't be added by `createWebHashHistory` + * createWebHashHistory('/folder/#/app/') // gives a url of `https://example.com/folder/#/app/` + * // you should avoid doing this because it changes the original url and breaks copying urls + * createWebHashHistory('/other-folder/') // gives a url of `https://example.com/other-folder/#` + * + * // at file:///usr/etc/folder/index.html + * // for locations with no `host`, the base is ignored + * createWebHashHistory('/iAmIgnored') // gives a url of `file:///usr/etc/folder/index.html#` + * ``` + */ +function createWebHashHistory(base) { + // Make sure this implementation is fine in terms of encoding, specially for IE11 + // for `file://`, directly use the pathname and ignore the base + // location.pathname contains an initial `/` even at the root: `https://example.com` + base = location.host ? base || location.pathname + location.search : ''; + // allow the user to provide a `#` in the middle: `/base/#/app` + if (!base.includes('#')) + base += '#'; + if (!base.endsWith('#/') && !base.endsWith('#')) { + warn(`A hash base must end with a "#":\n"${base}" should be "${base.replace(/#.*$/, '#')}".`); + } + return createWebHistory(base); +} + +function isRouteLocation(route) { + return typeof route === 'string' || (route && typeof route === 'object'); +} +function isRouteName(name) { + return typeof name === 'string' || typeof name === 'symbol'; +} + +/** + * Initial route location where the router is. Can be used in navigation guards + * to differentiate the initial navigation. + * + * @example + * ```js + * import { START_LOCATION } from 'vue-router' + * + * router.beforeEach((to, from) => { + * if (from === START_LOCATION) { + * // initial navigation + * } + * }) + * ``` + */ +const START_LOCATION_NORMALIZED = { + path: '/', + name: undefined, + params: {}, + query: {}, + hash: '', + fullPath: '/', + matched: [], + meta: {}, + redirectedFrom: undefined, +}; + +const NavigationFailureSymbol = Symbol('navigation failure' ); +/** + * Enumeration with all possible types for navigation failures. Can be passed to + * {@link isNavigationFailure} to check for specific failures. + */ +var NavigationFailureType; +(function (NavigationFailureType) { + /** + * An aborted navigation is a navigation that failed because a navigation + * guard returned `false` or called `next(false)` + */ + NavigationFailureType[NavigationFailureType["aborted"] = 4] = "aborted"; + /** + * A cancelled navigation is a navigation that failed because a more recent + * navigation finished started (not necessarily finished). + */ + NavigationFailureType[NavigationFailureType["cancelled"] = 8] = "cancelled"; + /** + * A duplicated navigation is a navigation that failed because it was + * initiated while already being at the exact same location. + */ + NavigationFailureType[NavigationFailureType["duplicated"] = 16] = "duplicated"; +})(NavigationFailureType || (NavigationFailureType = {})); +// DEV only debug messages +const ErrorTypeMessages = { + [1 /* ErrorTypes.MATCHER_NOT_FOUND */]({ location, currentLocation }) { + return `No match for\n ${JSON.stringify(location)}${currentLocation + ? '\nwhile being at\n' + JSON.stringify(currentLocation) + : ''}`; + }, + [2 /* ErrorTypes.NAVIGATION_GUARD_REDIRECT */]({ from, to, }) { + return `Redirected from "${from.fullPath}" to "${stringifyRoute(to)}" via a navigation guard.`; + }, + [4 /* ErrorTypes.NAVIGATION_ABORTED */]({ from, to }) { + return `Navigation aborted from "${from.fullPath}" to "${to.fullPath}" via a navigation guard.`; + }, + [8 /* ErrorTypes.NAVIGATION_CANCELLED */]({ from, to }) { + return `Navigation cancelled from "${from.fullPath}" to "${to.fullPath}" with a new navigation.`; + }, + [16 /* ErrorTypes.NAVIGATION_DUPLICATED */]({ from, to }) { + return `Avoided redundant navigation to current location: "${from.fullPath}".`; + }, +}; +function createRouterError(type, params) { + // keep full error messages in cjs versions + { + return assign(new Error(ErrorTypeMessages[type](params)), { + type, + [NavigationFailureSymbol]: true, + }, params); + } +} +function isNavigationFailure(error, type) { + return (error instanceof Error && + NavigationFailureSymbol in error && + (type == null || !!(error.type & type))); +} +const propertiesToLog = ['params', 'query', 'hash']; +function stringifyRoute(to) { + if (typeof to === 'string') + return to; + if ('path' in to) + return to.path; + const location = {}; + for (const key of propertiesToLog) { + if (key in to) + location[key] = to[key]; + } + return JSON.stringify(location, null, 2); +} + +// default pattern for a param: non-greedy everything but / +const BASE_PARAM_PATTERN = '[^/]+?'; +const BASE_PATH_PARSER_OPTIONS = { + sensitive: false, + strict: false, + start: true, + end: true, +}; +// Special Regex characters that must be escaped in static tokens +const REGEX_CHARS_RE = /[.+*?^${}()[\]/\\]/g; +/** + * Creates a path parser from an array of Segments (a segment is an array of Tokens) + * + * @param segments - array of segments returned by tokenizePath + * @param extraOptions - optional options for the regexp + * @returns a PathParser + */ +function tokensToParser(segments, extraOptions) { + const options = assign({}, BASE_PATH_PARSER_OPTIONS, extraOptions); + // the amount of scores is the same as the length of segments except for the root segment "/" + const score = []; + // the regexp as a string + let pattern = options.start ? '^' : ''; + // extracted keys + const keys = []; + for (const segment of segments) { + // the root segment needs special treatment + const segmentScores = segment.length ? [] : [90 /* PathScore.Root */]; + // allow trailing slash + if (options.strict && !segment.length) + pattern += '/'; + for (let tokenIndex = 0; tokenIndex < segment.length; tokenIndex++) { + const token = segment[tokenIndex]; + // resets the score if we are inside a sub-segment /:a-other-:b + let subSegmentScore = 40 /* PathScore.Segment */ + + (options.sensitive ? 0.25 /* PathScore.BonusCaseSensitive */ : 0); + if (token.type === 0 /* TokenType.Static */) { + // prepend the slash if we are starting a new segment + if (!tokenIndex) + pattern += '/'; + pattern += token.value.replace(REGEX_CHARS_RE, '\\$&'); + subSegmentScore += 40 /* PathScore.Static */; + } + else if (token.type === 1 /* TokenType.Param */) { + const { value, repeatable, optional, regexp } = token; + keys.push({ + name: value, + repeatable, + optional, + }); + const re = regexp ? regexp : BASE_PARAM_PATTERN; + // the user provided a custom regexp /:id(\\d+) + if (re !== BASE_PARAM_PATTERN) { + subSegmentScore += 10 /* PathScore.BonusCustomRegExp */; + // make sure the regexp is valid before using it + try { + new RegExp(`(${re})`); + } + catch (err) { + throw new Error(`Invalid custom RegExp for param "${value}" (${re}): ` + + err.message); + } + } + // when we repeat we must take care of the repeating leading slash + let subPattern = repeatable ? `((?:${re})(?:/(?:${re}))*)` : `(${re})`; + // prepend the slash if we are starting a new segment + if (!tokenIndex) + subPattern = + // avoid an optional / if there are more segments e.g. /:p?-static + // or /:p?-:p2 + optional && segment.length < 2 + ? `(?:/${subPattern})` + : '/' + subPattern; + if (optional) + subPattern += '?'; + pattern += subPattern; + subSegmentScore += 20 /* PathScore.Dynamic */; + if (optional) + subSegmentScore += -8 /* PathScore.BonusOptional */; + if (repeatable) + subSegmentScore += -20 /* PathScore.BonusRepeatable */; + if (re === '.*') + subSegmentScore += -50 /* PathScore.BonusWildcard */; + } + segmentScores.push(subSegmentScore); + } + // an empty array like /home/ -> [[{home}], []] + // if (!segment.length) pattern += '/' + score.push(segmentScores); + } + // only apply the strict bonus to the last score + if (options.strict && options.end) { + const i = score.length - 1; + score[i][score[i].length - 1] += 0.7000000000000001 /* PathScore.BonusStrict */; + } + // TODO: dev only warn double trailing slash + if (!options.strict) + pattern += '/?'; + if (options.end) + pattern += '$'; + // allow paths like /dynamic to only match dynamic or dynamic/... but not dynamic_something_else + else if (options.strict) + pattern += '(?:/|$)'; + const re = new RegExp(pattern, options.sensitive ? '' : 'i'); + function parse(path) { + const match = path.match(re); + const params = {}; + if (!match) + return null; + for (let i = 1; i < match.length; i++) { + const value = match[i] || ''; + const key = keys[i - 1]; + params[key.name] = value && key.repeatable ? value.split('/') : value; + } + return params; + } + function stringify(params) { + let path = ''; + // for optional parameters to allow to be empty + let avoidDuplicatedSlash = false; + for (const segment of segments) { + if (!avoidDuplicatedSlash || !path.endsWith('/')) + path += '/'; + avoidDuplicatedSlash = false; + for (const token of segment) { + if (token.type === 0 /* TokenType.Static */) { + path += token.value; + } + else if (token.type === 1 /* TokenType.Param */) { + const { value, repeatable, optional } = token; + const param = value in params ? params[value] : ''; + if (isArray(param) && !repeatable) { + throw new Error(`Provided param "${value}" is an array but it is not repeatable (* or + modifiers)`); + } + const text = isArray(param) + ? param.join('/') + : param; + if (!text) { + if (optional) { + // if we have more than one optional param like /:a?-static we don't need to care about the optional param + if (segment.length < 2) { + // remove the last slash as we could be at the end + if (path.endsWith('/')) + path = path.slice(0, -1); + // do not append a slash on the next iteration + else + avoidDuplicatedSlash = true; + } + } + else + throw new Error(`Missing required param "${value}"`); + } + path += text; + } + } + } + // avoid empty path when we have multiple optional params + return path || '/'; + } + return { + re, + score, + keys, + parse, + stringify, + }; +} +/** + * Compares an array of numbers as used in PathParser.score and returns a + * number. This function can be used to `sort` an array + * + * @param a - first array of numbers + * @param b - second array of numbers + * @returns 0 if both are equal, < 0 if a should be sorted first, > 0 if b + * should be sorted first + */ +function compareScoreArray(a, b) { + let i = 0; + while (i < a.length && i < b.length) { + const diff = b[i] - a[i]; + // only keep going if diff === 0 + if (diff) + return diff; + i++; + } + // if the last subsegment was Static, the shorter segments should be sorted first + // otherwise sort the longest segment first + if (a.length < b.length) { + return a.length === 1 && a[0] === 40 /* PathScore.Static */ + 40 /* PathScore.Segment */ + ? -1 + : 1; + } + else if (a.length > b.length) { + return b.length === 1 && b[0] === 40 /* PathScore.Static */ + 40 /* PathScore.Segment */ + ? 1 + : -1; + } + return 0; +} +/** + * Compare function that can be used with `sort` to sort an array of PathParser + * + * @param a - first PathParser + * @param b - second PathParser + * @returns 0 if both are equal, < 0 if a should be sorted first, > 0 if b + */ +function comparePathParserScore(a, b) { + let i = 0; + const aScore = a.score; + const bScore = b.score; + while (i < aScore.length && i < bScore.length) { + const comp = compareScoreArray(aScore[i], bScore[i]); + // do not return if both are equal + if (comp) + return comp; + i++; + } + if (Math.abs(bScore.length - aScore.length) === 1) { + if (isLastScoreNegative(aScore)) + return 1; + if (isLastScoreNegative(bScore)) + return -1; + } + // if a and b share the same score entries but b has more, sort b first + return bScore.length - aScore.length; + // this is the ternary version + // return aScore.length < bScore.length + // ? 1 + // : aScore.length > bScore.length + // ? -1 + // : 0 +} +/** + * This allows detecting splats at the end of a path: /home/:id(.*)* + * + * @param score - score to check + * @returns true if the last entry is negative + */ +function isLastScoreNegative(score) { + const last = score[score.length - 1]; + return score.length > 0 && last[last.length - 1] < 0; +} + +const ROOT_TOKEN = { + type: 0 /* TokenType.Static */, + value: '', +}; +const VALID_PARAM_RE = /[a-zA-Z0-9_]/; +// After some profiling, the cache seems to be unnecessary because tokenizePath +// (the slowest part of adding a route) is very fast +// const tokenCache = new Map() +function tokenizePath(path) { + if (!path) + return [[]]; + if (path === '/') + return [[ROOT_TOKEN]]; + if (!path.startsWith('/')) { + throw new Error(`Route paths should start with a "/": "${path}" should be "/${path}".` + ); + } + // if (tokenCache.has(path)) return tokenCache.get(path)! + function crash(message) { + throw new Error(`ERR (${state})/"${buffer}": ${message}`); + } + let state = 0 /* TokenizerState.Static */; + let previousState = state; + const tokens = []; + // the segment will always be valid because we get into the initial state + // with the leading / + let segment; + function finalizeSegment() { + if (segment) + tokens.push(segment); + segment = []; + } + // index on the path + let i = 0; + // char at index + let char; + // buffer of the value read + let buffer = ''; + // custom regexp for a param + let customRe = ''; + function consumeBuffer() { + if (!buffer) + return; + if (state === 0 /* TokenizerState.Static */) { + segment.push({ + type: 0 /* TokenType.Static */, + value: buffer, + }); + } + else if (state === 1 /* TokenizerState.Param */ || + state === 2 /* TokenizerState.ParamRegExp */ || + state === 3 /* TokenizerState.ParamRegExpEnd */) { + if (segment.length > 1 && (char === '*' || char === '+')) + crash(`A repeatable param (${buffer}) must be alone in its segment. eg: '/:ids+.`); + segment.push({ + type: 1 /* TokenType.Param */, + value: buffer, + regexp: customRe, + repeatable: char === '*' || char === '+', + optional: char === '*' || char === '?', + }); + } + else { + crash('Invalid state to consume buffer'); + } + buffer = ''; + } + function addCharToBuffer() { + buffer += char; + } + while (i < path.length) { + char = path[i++]; + if (char === '\\' && state !== 2 /* TokenizerState.ParamRegExp */) { + previousState = state; + state = 4 /* TokenizerState.EscapeNext */; + continue; + } + switch (state) { + case 0 /* TokenizerState.Static */: + if (char === '/') { + if (buffer) { + consumeBuffer(); + } + finalizeSegment(); + } + else if (char === ':') { + consumeBuffer(); + state = 1 /* TokenizerState.Param */; + } + else { + addCharToBuffer(); + } + break; + case 4 /* TokenizerState.EscapeNext */: + addCharToBuffer(); + state = previousState; + break; + case 1 /* TokenizerState.Param */: + if (char === '(') { + state = 2 /* TokenizerState.ParamRegExp */; + } + else if (VALID_PARAM_RE.test(char)) { + addCharToBuffer(); + } + else { + consumeBuffer(); + state = 0 /* TokenizerState.Static */; + // go back one character if we were not modifying + if (char !== '*' && char !== '?' && char !== '+') + i--; + } + break; + case 2 /* TokenizerState.ParamRegExp */: + // TODO: is it worth handling nested regexp? like :p(?:prefix_([^/]+)_suffix) + // it already works by escaping the closing ) + // https://paths.esm.dev/?p=AAMeJbiAwQEcDKbAoAAkP60PG2R6QAvgNaA6AFACM2ABuQBB# + // is this really something people need since you can also write + // /prefix_:p()_suffix + if (char === ')') { + // handle the escaped ) + if (customRe[customRe.length - 1] == '\\') + customRe = customRe.slice(0, -1) + char; + else + state = 3 /* TokenizerState.ParamRegExpEnd */; + } + else { + customRe += char; + } + break; + case 3 /* TokenizerState.ParamRegExpEnd */: + // same as finalizing a param + consumeBuffer(); + state = 0 /* TokenizerState.Static */; + // go back one character if we were not modifying + if (char !== '*' && char !== '?' && char !== '+') + i--; + customRe = ''; + break; + default: + crash('Unknown state'); + break; + } + } + if (state === 2 /* TokenizerState.ParamRegExp */) + crash(`Unfinished custom RegExp for param "${buffer}"`); + consumeBuffer(); + finalizeSegment(); + // tokenCache.set(path, tokens) + return tokens; +} + +function createRouteRecordMatcher(record, parent, options) { + const parser = tokensToParser(tokenizePath(record.path), options); + // warn against params with the same name + { + const existingKeys = new Set(); + for (const key of parser.keys) { + if (existingKeys.has(key.name)) + warn(`Found duplicated params with name "${key.name}" for path "${record.path}". Only the last one will be available on "$route.params".`); + existingKeys.add(key.name); + } + } + const matcher = assign(parser, { + record, + parent, + // these needs to be populated by the parent + children: [], + alias: [], + }); + if (parent) { + // both are aliases or both are not aliases + // we don't want to mix them because the order is used when + // passing originalRecord in Matcher.addRoute + if (!matcher.record.aliasOf === !parent.record.aliasOf) + parent.children.push(matcher); + } + return matcher; +} + +/** + * Creates a Router Matcher. + * + * @internal + * @param routes - array of initial routes + * @param globalOptions - global route options + */ +function createRouterMatcher(routes, globalOptions) { + // normalized ordered array of matchers + const matchers = []; + const matcherMap = new Map(); + globalOptions = mergeOptions({ strict: false, end: true, sensitive: false }, globalOptions); + function getRecordMatcher(name) { + return matcherMap.get(name); + } + function addRoute(record, parent, originalRecord) { + // used later on to remove by name + const isRootAdd = !originalRecord; + const mainNormalizedRecord = normalizeRouteRecord(record); + { + checkChildMissingNameWithEmptyPath(mainNormalizedRecord, parent); + } + // we might be the child of an alias + mainNormalizedRecord.aliasOf = originalRecord && originalRecord.record; + const options = mergeOptions(globalOptions, record); + // generate an array of records to correctly handle aliases + const normalizedRecords = [ + mainNormalizedRecord, + ]; + if ('alias' in record) { + const aliases = typeof record.alias === 'string' ? [record.alias] : record.alias; + for (const alias of aliases) { + normalizedRecords.push(assign({}, mainNormalizedRecord, { + // this allows us to hold a copy of the `components` option + // so that async components cache is hold on the original record + components: originalRecord + ? originalRecord.record.components + : mainNormalizedRecord.components, + path: alias, + // we might be the child of an alias + aliasOf: originalRecord + ? originalRecord.record + : mainNormalizedRecord, + // the aliases are always of the same kind as the original since they + // are defined on the same record + })); + } + } + let matcher; + let originalMatcher; + for (const normalizedRecord of normalizedRecords) { + const { path } = normalizedRecord; + // Build up the path for nested routes if the child isn't an absolute + // route. Only add the / delimiter if the child path isn't empty and if the + // parent path doesn't have a trailing slash + if (parent && path[0] !== '/') { + const parentPath = parent.record.path; + const connectingSlash = parentPath[parentPath.length - 1] === '/' ? '' : '/'; + normalizedRecord.path = + parent.record.path + (path && connectingSlash + path); + } + if (normalizedRecord.path === '*') { + throw new Error('Catch all routes ("*") must now be defined using a param with a custom regexp.\n' + + 'See more at https://next.router.vuejs.org/guide/migration/#removed-star-or-catch-all-routes.'); + } + // create the object beforehand, so it can be passed to children + matcher = createRouteRecordMatcher(normalizedRecord, parent, options); + if (parent && path[0] === '/') + checkMissingParamsInAbsolutePath(matcher, parent); + // if we are an alias we must tell the original record that we exist, + // so we can be removed + if (originalRecord) { + originalRecord.alias.push(matcher); + { + checkSameParams(originalRecord, matcher); + } + } + else { + // otherwise, the first record is the original and others are aliases + originalMatcher = originalMatcher || matcher; + if (originalMatcher !== matcher) + originalMatcher.alias.push(matcher); + // remove the route if named and only for the top record (avoid in nested calls) + // this works because the original record is the first one + if (isRootAdd && record.name && !isAliasRecord(matcher)) + removeRoute(record.name); + } + if (mainNormalizedRecord.children) { + const children = mainNormalizedRecord.children; + for (let i = 0; i < children.length; i++) { + addRoute(children[i], matcher, originalRecord && originalRecord.children[i]); + } + } + // if there was no original record, then the first one was not an alias and all + // other aliases (if any) need to reference this record when adding children + originalRecord = originalRecord || matcher; + // TODO: add normalized records for more flexibility + // if (parent && isAliasRecord(originalRecord)) { + // parent.children.push(originalRecord) + // } + // Avoid adding a record that doesn't display anything. This allows passing through records without a component to + // not be reached and pass through the catch all route + if ((matcher.record.components && + Object.keys(matcher.record.components).length) || + matcher.record.name || + matcher.record.redirect) { + insertMatcher(matcher); + } + } + return originalMatcher + ? () => { + // since other matchers are aliases, they should be removed by the original matcher + removeRoute(originalMatcher); + } + : noop; + } + function removeRoute(matcherRef) { + if (isRouteName(matcherRef)) { + const matcher = matcherMap.get(matcherRef); + if (matcher) { + matcherMap.delete(matcherRef); + matchers.splice(matchers.indexOf(matcher), 1); + matcher.children.forEach(removeRoute); + matcher.alias.forEach(removeRoute); + } + } + else { + const index = matchers.indexOf(matcherRef); + if (index > -1) { + matchers.splice(index, 1); + if (matcherRef.record.name) + matcherMap.delete(matcherRef.record.name); + matcherRef.children.forEach(removeRoute); + matcherRef.alias.forEach(removeRoute); + } + } + } + function getRoutes() { + return matchers; + } + function insertMatcher(matcher) { + let i = 0; + while (i < matchers.length && + comparePathParserScore(matcher, matchers[i]) >= 0 && + // Adding children with empty path should still appear before the parent + // https://github.com/vuejs/router/issues/1124 + (matcher.record.path !== matchers[i].record.path || + !isRecordChildOf(matcher, matchers[i]))) + i++; + matchers.splice(i, 0, matcher); + // only add the original record to the name map + if (matcher.record.name && !isAliasRecord(matcher)) + matcherMap.set(matcher.record.name, matcher); + } + function resolve(location, currentLocation) { + let matcher; + let params = {}; + let path; + let name; + if ('name' in location && location.name) { + matcher = matcherMap.get(location.name); + if (!matcher) + throw createRouterError(1 /* ErrorTypes.MATCHER_NOT_FOUND */, { + location, + }); + // warn if the user is passing invalid params so they can debug it better when they get removed + { + const invalidParams = Object.keys(location.params || {}).filter(paramName => !matcher.keys.find(k => k.name === paramName)); + if (invalidParams.length) { + warn(`Discarded invalid param(s) "${invalidParams.join('", "')}" when navigating. See https://github.com/vuejs/router/blob/main/packages/router/CHANGELOG.md#414-2022-08-22 for more details.`); + } + } + name = matcher.record.name; + params = assign( + // paramsFromLocation is a new object + paramsFromLocation(currentLocation.params, + // only keep params that exist in the resolved location + // TODO: only keep optional params coming from a parent record + matcher.keys.filter(k => !k.optional).map(k => k.name)), + // discard any existing params in the current location that do not exist here + // #1497 this ensures better active/exact matching + location.params && + paramsFromLocation(location.params, matcher.keys.map(k => k.name))); + // throws if cannot be stringified + path = matcher.stringify(params); + } + else if ('path' in location) { + // no need to resolve the path with the matcher as it was provided + // this also allows the user to control the encoding + path = location.path; + if (!path.startsWith('/')) { + warn(`The Matcher cannot resolve relative paths but received "${path}". Unless you directly called \`matcher.resolve("${path}")\`, this is probably a bug in vue-router. Please open an issue at https://github.com/vuejs/router/issues/new/choose.`); + } + matcher = matchers.find(m => m.re.test(path)); + // matcher should have a value after the loop + if (matcher) { + // we know the matcher works because we tested the regexp + params = matcher.parse(path); + name = matcher.record.name; + } + // location is a relative path + } + else { + // match by name or path of current route + matcher = currentLocation.name + ? matcherMap.get(currentLocation.name) + : matchers.find(m => m.re.test(currentLocation.path)); + if (!matcher) + throw createRouterError(1 /* ErrorTypes.MATCHER_NOT_FOUND */, { + location, + currentLocation, + }); + name = matcher.record.name; + // since we are navigating to the same location, we don't need to pick the + // params like when `name` is provided + params = assign({}, currentLocation.params, location.params); + path = matcher.stringify(params); + } + const matched = []; + let parentMatcher = matcher; + while (parentMatcher) { + // reversed order so parents are at the beginning + matched.unshift(parentMatcher.record); + parentMatcher = parentMatcher.parent; + } + return { + name, + path, + params, + matched, + meta: mergeMetaFields(matched), + }; + } + // add initial routes + routes.forEach(route => addRoute(route)); + return { addRoute, resolve, removeRoute, getRoutes, getRecordMatcher }; +} +function paramsFromLocation(params, keys) { + const newParams = {}; + for (const key of keys) { + if (key in params) + newParams[key] = params[key]; + } + return newParams; +} +/** + * Normalizes a RouteRecordRaw. Creates a copy + * + * @param record + * @returns the normalized version + */ +function normalizeRouteRecord(record) { + return { + path: record.path, + redirect: record.redirect, + name: record.name, + meta: record.meta || {}, + aliasOf: undefined, + beforeEnter: record.beforeEnter, + props: normalizeRecordProps(record), + children: record.children || [], + instances: {}, + leaveGuards: new Set(), + updateGuards: new Set(), + enterCallbacks: {}, + components: 'components' in record + ? record.components || null + : record.component && { default: record.component }, + }; +} +/** + * Normalize the optional `props` in a record to always be an object similar to + * components. Also accept a boolean for components. + * @param record + */ +function normalizeRecordProps(record) { + const propsObject = {}; + // props does not exist on redirect records, but we can set false directly + const props = record.props || false; + if ('component' in record) { + propsObject.default = props; + } + else { + // NOTE: we could also allow a function to be applied to every component. + // Would need user feedback for use cases + for (const name in record.components) + propsObject[name] = typeof props === 'object' ? props[name] : props; + } + return propsObject; +} +/** + * Checks if a record or any of its parent is an alias + * @param record + */ +function isAliasRecord(record) { + while (record) { + if (record.record.aliasOf) + return true; + record = record.parent; + } + return false; +} +/** + * Merge meta fields of an array of records + * + * @param matched - array of matched records + */ +function mergeMetaFields(matched) { + return matched.reduce((meta, record) => assign(meta, record.meta), {}); +} +function mergeOptions(defaults, partialOptions) { + const options = {}; + for (const key in defaults) { + options[key] = key in partialOptions ? partialOptions[key] : defaults[key]; + } + return options; +} +function isSameParam(a, b) { + return (a.name === b.name && + a.optional === b.optional && + a.repeatable === b.repeatable); +} +/** + * Check if a path and its alias have the same required params + * + * @param a - original record + * @param b - alias record + */ +function checkSameParams(a, b) { + for (const key of a.keys) { + if (!key.optional && !b.keys.find(isSameParam.bind(null, key))) + return warn(`Alias "${b.record.path}" and the original record: "${a.record.path}" must have the exact same param named "${key.name}"`); + } + for (const key of b.keys) { + if (!key.optional && !a.keys.find(isSameParam.bind(null, key))) + return warn(`Alias "${b.record.path}" and the original record: "${a.record.path}" must have the exact same param named "${key.name}"`); + } +} +/** + * A route with a name and a child with an empty path without a name should warn when adding the route + * + * @param mainNormalizedRecord - RouteRecordNormalized + * @param parent - RouteRecordMatcher + */ +function checkChildMissingNameWithEmptyPath(mainNormalizedRecord, parent) { + if (parent && + parent.record.name && + !mainNormalizedRecord.name && + !mainNormalizedRecord.path) { + warn(`The route named "${String(parent.record.name)}" has a child without a name and an empty path. Using that name won't render the empty path child so you probably want to move the name to the child instead. If this is intentional, add a name to the child route to remove the warning.`); + } +} +function checkMissingParamsInAbsolutePath(record, parent) { + for (const key of parent.keys) { + if (!record.keys.find(isSameParam.bind(null, key))) + return warn(`Absolute path "${record.record.path}" must have the exact same param named "${key.name}" as its parent "${parent.record.path}".`); + } +} +function isRecordChildOf(record, parent) { + return parent.children.some(child => child === record || isRecordChildOf(record, child)); +} + +/** + * Encoding Rules ⣠= Space Path: ⣠" < > # ? { } Query: ⣠" < > # & = Hash: ⣠" + * < > ` + * + * On top of that, the RFC3986 (https://tools.ietf.org/html/rfc3986#section-2.2) + * defines some extra characters to be encoded. Most browsers do not encode them + * in encodeURI https://github.com/whatwg/url/issues/369, so it may be safer to + * also encode `!'()*`. Leaving un-encoded only ASCII alphanumeric(`a-zA-Z0-9`) + * plus `-._~`. This extra safety should be applied to query by patching the + * string returned by encodeURIComponent encodeURI also encodes `[\]^`. `\` + * should be encoded to avoid ambiguity. Browsers (IE, FF, C) transform a `\` + * into a `/` if directly typed in. The _backtick_ (`````) should also be + * encoded everywhere because some browsers like FF encode it when directly + * written while others don't. Safari and IE don't encode ``"<>{}``` in hash. + */ +// const EXTRA_RESERVED_RE = /[!'()*]/g +// const encodeReservedReplacer = (c: string) => '%' + c.charCodeAt(0).toString(16) +const HASH_RE = /#/g; // %23 +const AMPERSAND_RE = /&/g; // %26 +const SLASH_RE = /\//g; // %2F +const EQUAL_RE = /=/g; // %3D +const IM_RE = /\?/g; // %3F +const PLUS_RE = /\+/g; // %2B +/** + * NOTE: It's not clear to me if we should encode the + symbol in queries, it + * seems to be less flexible than not doing so and I can't find out the legacy + * systems requiring this for regular requests like text/html. In the standard, + * the encoding of the plus character is only mentioned for + * application/x-www-form-urlencoded + * (https://url.spec.whatwg.org/#urlencoded-parsing) and most browsers seems lo + * leave the plus character as is in queries. To be more flexible, we allow the + * plus character on the query, but it can also be manually encoded by the user. + * + * Resources: + * - https://url.spec.whatwg.org/#urlencoded-parsing + * - https://stackoverflow.com/questions/1634271/url-encoding-the-space-character-or-20 + */ +const ENC_BRACKET_OPEN_RE = /%5B/g; // [ +const ENC_BRACKET_CLOSE_RE = /%5D/g; // ] +const ENC_CARET_RE = /%5E/g; // ^ +const ENC_BACKTICK_RE = /%60/g; // ` +const ENC_CURLY_OPEN_RE = /%7B/g; // { +const ENC_PIPE_RE = /%7C/g; // | +const ENC_CURLY_CLOSE_RE = /%7D/g; // } +const ENC_SPACE_RE = /%20/g; // } +/** + * Encode characters that need to be encoded on the path, search and hash + * sections of the URL. + * + * @internal + * @param text - string to encode + * @returns encoded string + */ +function commonEncode(text) { + return encodeURI('' + text) + .replace(ENC_PIPE_RE, '|') + .replace(ENC_BRACKET_OPEN_RE, '[') + .replace(ENC_BRACKET_CLOSE_RE, ']'); +} +/** + * Encode characters that need to be encoded on the hash section of the URL. + * + * @param text - string to encode + * @returns encoded string + */ +function encodeHash(text) { + return commonEncode(text) + .replace(ENC_CURLY_OPEN_RE, '{') + .replace(ENC_CURLY_CLOSE_RE, '}') + .replace(ENC_CARET_RE, '^'); +} +/** + * Encode characters that need to be encoded query values on the query + * section of the URL. + * + * @param text - string to encode + * @returns encoded string + */ +function encodeQueryValue(text) { + return (commonEncode(text) + // Encode the space as +, encode the + to differentiate it from the space + .replace(PLUS_RE, '%2B') + .replace(ENC_SPACE_RE, '+') + .replace(HASH_RE, '%23') + .replace(AMPERSAND_RE, '%26') + .replace(ENC_BACKTICK_RE, '`') + .replace(ENC_CURLY_OPEN_RE, '{') + .replace(ENC_CURLY_CLOSE_RE, '}') + .replace(ENC_CARET_RE, '^')); +} +/** + * Like `encodeQueryValue` but also encodes the `=` character. + * + * @param text - string to encode + */ +function encodeQueryKey(text) { + return encodeQueryValue(text).replace(EQUAL_RE, '%3D'); +} +/** + * Encode characters that need to be encoded on the path section of the URL. + * + * @param text - string to encode + * @returns encoded string + */ +function encodePath(text) { + return commonEncode(text).replace(HASH_RE, '%23').replace(IM_RE, '%3F'); +} +/** + * Encode characters that need to be encoded on the path section of the URL as a + * param. This function encodes everything {@link encodePath} does plus the + * slash (`/`) character. If `text` is `null` or `undefined`, returns an empty + * string instead. + * + * @param text - string to encode + * @returns encoded string + */ +function encodeParam(text) { + return text == null ? '' : encodePath(text).replace(SLASH_RE, '%2F'); +} +/** + * Decode text using `decodeURIComponent`. Returns the original text if it + * fails. + * + * @param text - string to decode + * @returns decoded string + */ +function decode(text) { + try { + return decodeURIComponent('' + text); + } + catch (err) { + warn(`Error decoding "${text}". Using original value`); + } + return '' + text; +} + +/** + * Transforms a queryString into a {@link LocationQuery} object. Accept both, a + * version with the leading `?` and without Should work as URLSearchParams + + * @internal + * + * @param search - search string to parse + * @returns a query object + */ +function parseQuery(search) { + const query = {}; + // avoid creating an object with an empty key and empty value + // because of split('&') + if (search === '' || search === '?') + return query; + const hasLeadingIM = search[0] === '?'; + const searchParams = (hasLeadingIM ? search.slice(1) : search).split('&'); + for (let i = 0; i < searchParams.length; ++i) { + // pre decode the + into space + const searchParam = searchParams[i].replace(PLUS_RE, ' '); + // allow the = character + const eqPos = searchParam.indexOf('='); + const key = decode(eqPos < 0 ? searchParam : searchParam.slice(0, eqPos)); + const value = eqPos < 0 ? null : decode(searchParam.slice(eqPos + 1)); + if (key in query) { + // an extra variable for ts types + let currentValue = query[key]; + if (!isArray(currentValue)) { + currentValue = query[key] = [currentValue]; + } + currentValue.push(value); + } + else { + query[key] = value; + } + } + return query; +} +/** + * Stringifies a {@link LocationQueryRaw} object. Like `URLSearchParams`, it + * doesn't prepend a `?` + * + * @internal + * + * @param query - query object to stringify + * @returns string version of the query without the leading `?` + */ +function stringifyQuery(query) { + let search = ''; + for (let key in query) { + const value = query[key]; + key = encodeQueryKey(key); + if (value == null) { + // only null adds the value + if (value !== undefined) { + search += (search.length ? '&' : '') + key; + } + continue; + } + // keep null values + const values = isArray(value) + ? value.map(v => v && encodeQueryValue(v)) + : [value && encodeQueryValue(value)]; + values.forEach(value => { + // skip undefined values in arrays as if they were not present + // smaller code than using filter + if (value !== undefined) { + // only append & with non-empty search + search += (search.length ? '&' : '') + key; + if (value != null) + search += '=' + value; + } + }); + } + return search; +} +/** + * Transforms a {@link LocationQueryRaw} into a {@link LocationQuery} by casting + * numbers into strings, removing keys with an undefined value and replacing + * undefined with null in arrays + * + * @param query - query object to normalize + * @returns a normalized query object + */ +function normalizeQuery(query) { + const normalizedQuery = {}; + for (const key in query) { + const value = query[key]; + if (value !== undefined) { + normalizedQuery[key] = isArray(value) + ? value.map(v => (v == null ? null : '' + v)) + : value == null + ? value + : '' + value; + } + } + return normalizedQuery; +} + +/** + * RouteRecord being rendered by the closest ancestor Router View. Used for + * `onBeforeRouteUpdate` and `onBeforeRouteLeave`. rvlm stands for Router View + * Location Matched + * + * @internal + */ +const matchedRouteKey = Symbol('router view location matched' ); +/** + * Allows overriding the router view depth to control which component in + * `matched` is rendered. rvd stands for Router View Depth + * + * @internal + */ +const viewDepthKey = Symbol('router view depth' ); +/** + * Allows overriding the router instance returned by `useRouter` in tests. r + * stands for router + * + * @internal + */ +const routerKey = Symbol('router' ); +/** + * Allows overriding the current route returned by `useRoute` in tests. rl + * stands for route location + * + * @internal + */ +const routeLocationKey = Symbol('route location' ); +/** + * Allows overriding the current route used by router-view. Internally this is + * used when the `route` prop is passed. + * + * @internal + */ +const routerViewLocationKey = Symbol('router view location' ); + +/** + * Create a list of callbacks that can be reset. Used to create before and after navigation guards list + */ +function useCallbacks() { + let handlers = []; + function add(handler) { + handlers.push(handler); + return () => { + const i = handlers.indexOf(handler); + if (i > -1) + handlers.splice(i, 1); + }; + } + function reset() { + handlers = []; + } + return { + add, + list: () => handlers.slice(), + reset, + }; +} + +function registerGuard(record, name, guard) { + const removeFromList = () => { + record[name].delete(guard); + }; + onUnmounted(removeFromList); + onDeactivated(removeFromList); + onActivated(() => { + record[name].add(guard); + }); + record[name].add(guard); +} +/** + * Add a navigation guard that triggers whenever the component for the current + * location is about to be left. Similar to {@link beforeRouteLeave} but can be + * used in any component. The guard is removed when the component is unmounted. + * + * @param leaveGuard - {@link NavigationGuard} + */ +function onBeforeRouteLeave(leaveGuard) { + if (!getCurrentInstance()) { + warn('getCurrentInstance() returned null. onBeforeRouteLeave() must be called at the top of a setup function'); + return; + } + const activeRecord = inject(matchedRouteKey, + // to avoid warning + {}).value; + if (!activeRecord) { + warn('No active route record was found when calling `onBeforeRouteLeave()`. Make sure you call this function inside a component child of . Maybe you called it inside of App.vue?'); + return; + } + registerGuard(activeRecord, 'leaveGuards', leaveGuard); +} +/** + * Add a navigation guard that triggers whenever the current location is about + * to be updated. Similar to {@link beforeRouteUpdate} but can be used in any + * component. The guard is removed when the component is unmounted. + * + * @param updateGuard - {@link NavigationGuard} + */ +function onBeforeRouteUpdate(updateGuard) { + if (!getCurrentInstance()) { + warn('getCurrentInstance() returned null. onBeforeRouteUpdate() must be called at the top of a setup function'); + return; + } + const activeRecord = inject(matchedRouteKey, + // to avoid warning + {}).value; + if (!activeRecord) { + warn('No active route record was found when calling `onBeforeRouteUpdate()`. Make sure you call this function inside a component child of . Maybe you called it inside of App.vue?'); + return; + } + registerGuard(activeRecord, 'updateGuards', updateGuard); +} +function guardToPromiseFn(guard, to, from, record, name) { + // keep a reference to the enterCallbackArray to prevent pushing callbacks if a new navigation took place + const enterCallbackArray = record && + // name is defined if record is because of the function overload + (record.enterCallbacks[name] = record.enterCallbacks[name] || []); + return () => new Promise((resolve, reject) => { + const next = (valid) => { + if (valid === false) { + reject(createRouterError(4 /* ErrorTypes.NAVIGATION_ABORTED */, { + from, + to, + })); + } + else if (valid instanceof Error) { + reject(valid); + } + else if (isRouteLocation(valid)) { + reject(createRouterError(2 /* ErrorTypes.NAVIGATION_GUARD_REDIRECT */, { + from: to, + to: valid, + })); + } + else { + if (enterCallbackArray && + // since enterCallbackArray is truthy, both record and name also are + record.enterCallbacks[name] === enterCallbackArray && + typeof valid === 'function') { + enterCallbackArray.push(valid); + } + resolve(); + } + }; + // wrapping with Promise.resolve allows it to work with both async and sync guards + const guardReturn = guard.call(record && record.instances[name], to, from, canOnlyBeCalledOnce(next, to, from) ); + let guardCall = Promise.resolve(guardReturn); + if (guard.length < 3) + guardCall = guardCall.then(next); + if (guard.length > 2) { + const message = `The "next" callback was never called inside of ${guard.name ? '"' + guard.name + '"' : ''}:\n${guard.toString()}\n. If you are returning a value instead of calling "next", make sure to remove the "next" parameter from your function.`; + if (typeof guardReturn === 'object' && 'then' in guardReturn) { + guardCall = guardCall.then(resolvedValue => { + // @ts-expect-error: _called is added at canOnlyBeCalledOnce + if (!next._called) { + warn(message); + return Promise.reject(new Error('Invalid navigation guard')); + } + return resolvedValue; + }); + } + else if (guardReturn !== undefined) { + // @ts-expect-error: _called is added at canOnlyBeCalledOnce + if (!next._called) { + warn(message); + reject(new Error('Invalid navigation guard')); + return; + } + } + } + guardCall.catch(err => reject(err)); + }); +} +function canOnlyBeCalledOnce(next, to, from) { + let called = 0; + return function () { + if (called++ === 1) + warn(`The "next" callback was called more than once in one navigation guard when going from "${from.fullPath}" to "${to.fullPath}". It should be called exactly one time in each navigation guard. This will fail in production.`); + // @ts-expect-error: we put it in the original one because it's easier to check + next._called = true; + if (called === 1) + next.apply(null, arguments); + }; +} +function extractComponentsGuards(matched, guardType, to, from) { + const guards = []; + for (const record of matched) { + if (!record.components && !record.children.length) { + warn(`Record with path "${record.path}" is either missing a "component(s)"` + + ` or "children" property.`); + } + for (const name in record.components) { + let rawComponent = record.components[name]; + { + if (!rawComponent || + (typeof rawComponent !== 'object' && + typeof rawComponent !== 'function')) { + warn(`Component "${name}" in record with path "${record.path}" is not` + + ` a valid component. Received "${String(rawComponent)}".`); + // throw to ensure we stop here but warn to ensure the message isn't + // missed by the user + throw new Error('Invalid route component'); + } + else if ('then' in rawComponent) { + // warn if user wrote import('/component.vue') instead of () => + // import('./component.vue') + warn(`Component "${name}" in record with path "${record.path}" is a ` + + `Promise instead of a function that returns a Promise. Did you ` + + `write "import('./MyPage.vue')" instead of ` + + `"() => import('./MyPage.vue')" ? This will break in ` + + `production if not fixed.`); + const promise = rawComponent; + rawComponent = () => promise; + } + else if (rawComponent.__asyncLoader && + // warn only once per component + !rawComponent.__warnedDefineAsync) { + rawComponent.__warnedDefineAsync = true; + warn(`Component "${name}" in record with path "${record.path}" is defined ` + + `using "defineAsyncComponent()". ` + + `Write "() => import('./MyPage.vue')" instead of ` + + `"defineAsyncComponent(() => import('./MyPage.vue'))".`); + } + } + // skip update and leave guards if the route component is not mounted + if (guardType !== 'beforeRouteEnter' && !record.instances[name]) + continue; + if (isRouteComponent(rawComponent)) { + // __vccOpts is added by vue-class-component and contain the regular options + const options = rawComponent.__vccOpts || rawComponent; + const guard = options[guardType]; + guard && guards.push(guardToPromiseFn(guard, to, from, record, name)); + } + else { + // start requesting the chunk already + let componentPromise = rawComponent(); + if (!('catch' in componentPromise)) { + warn(`Component "${name}" in record with path "${record.path}" is a function that does not return a Promise. If you were passing a functional component, make sure to add a "displayName" to the component. This will break in production if not fixed.`); + componentPromise = Promise.resolve(componentPromise); + } + guards.push(() => componentPromise.then(resolved => { + if (!resolved) + return Promise.reject(new Error(`Couldn't resolve component "${name}" at "${record.path}"`)); + const resolvedComponent = isESModule(resolved) + ? resolved.default + : resolved; + // replace the function with the resolved component + // cannot be null or undefined because we went into the for loop + record.components[name] = resolvedComponent; + // __vccOpts is added by vue-class-component and contain the regular options + const options = resolvedComponent.__vccOpts || resolvedComponent; + const guard = options[guardType]; + return guard && guardToPromiseFn(guard, to, from, record, name)(); + })); + } + } + } + return guards; +} +/** + * Allows differentiating lazy components from functional components and vue-class-component + * @internal + * + * @param component + */ +function isRouteComponent(component) { + return (typeof component === 'object' || + 'displayName' in component || + 'props' in component || + '__vccOpts' in component); +} +/** + * Ensures a route is loaded, so it can be passed as o prop to ``. + * + * @param route - resolved route to load + */ +function loadRouteLocation(route) { + return route.matched.every(record => record.redirect) + ? Promise.reject(new Error('Cannot load a route that redirects.')) + : Promise.all(route.matched.map(record => record.components && + Promise.all(Object.keys(record.components).reduce((promises, name) => { + const rawComponent = record.components[name]; + if (typeof rawComponent === 'function' && + !('displayName' in rawComponent)) { + promises.push(rawComponent().then(resolved => { + if (!resolved) + return Promise.reject(new Error(`Couldn't resolve component "${name}" at "${record.path}". Ensure you passed a function that returns a promise.`)); + const resolvedComponent = isESModule(resolved) + ? resolved.default + : resolved; + // replace the function with the resolved component + // cannot be null or undefined because we went into the for loop + record.components[name] = resolvedComponent; + return; + })); + } + return promises; + }, [])))).then(() => route); +} + +// TODO: we could allow currentRoute as a prop to expose `isActive` and +// `isExactActive` behavior should go through an RFC +function useLink(props) { + const router = inject(routerKey); + const currentRoute = inject(routeLocationKey); + const route = computed(() => router.resolve(unref(props.to))); + const activeRecordIndex = computed(() => { + const { matched } = route.value; + const { length } = matched; + const routeMatched = matched[length - 1]; + const currentMatched = currentRoute.matched; + if (!routeMatched || !currentMatched.length) + return -1; + const index = currentMatched.findIndex(isSameRouteRecord.bind(null, routeMatched)); + if (index > -1) + return index; + // possible parent record + const parentRecordPath = getOriginalPath(matched[length - 2]); + return ( + // we are dealing with nested routes + length > 1 && + // if the parent and matched route have the same path, this link is + // referring to the empty child. Or we currently are on a different + // child of the same parent + getOriginalPath(routeMatched) === parentRecordPath && + // avoid comparing the child with its parent + currentMatched[currentMatched.length - 1].path !== parentRecordPath + ? currentMatched.findIndex(isSameRouteRecord.bind(null, matched[length - 2])) + : index); + }); + const isActive = computed(() => activeRecordIndex.value > -1 && + includesParams(currentRoute.params, route.value.params)); + const isExactActive = computed(() => activeRecordIndex.value > -1 && + activeRecordIndex.value === currentRoute.matched.length - 1 && + isSameRouteLocationParams(currentRoute.params, route.value.params)); + function navigate(e = {}) { + if (guardEvent(e)) { + return router[unref(props.replace) ? 'replace' : 'push'](unref(props.to) + // avoid uncaught errors are they are logged anyway + ).catch(noop); + } + return Promise.resolve(); + } + // devtools only + if (isBrowser) { + const instance = getCurrentInstance(); + if (instance) { + const linkContextDevtools = { + route: route.value, + isActive: isActive.value, + isExactActive: isExactActive.value, + }; + // @ts-expect-error: this is internal + instance.__vrl_devtools = instance.__vrl_devtools || []; + // @ts-expect-error: this is internal + instance.__vrl_devtools.push(linkContextDevtools); + watchEffect(() => { + linkContextDevtools.route = route.value; + linkContextDevtools.isActive = isActive.value; + linkContextDevtools.isExactActive = isExactActive.value; + }, { flush: 'post' }); + } + } + /** + * NOTE: update {@link _RouterLinkI}'s `$slots` type when updating this + */ + return { + route, + href: computed(() => route.value.href), + isActive, + isExactActive, + navigate, + }; +} +const RouterLinkImpl = /*#__PURE__*/ defineComponent({ + name: 'RouterLink', + compatConfig: { MODE: 3 }, + props: { + to: { + type: [String, Object], + required: true, + }, + replace: Boolean, + activeClass: String, + // inactiveClass: String, + exactActiveClass: String, + custom: Boolean, + ariaCurrentValue: { + type: String, + default: 'page', + }, + }, + useLink, + setup(props, { slots }) { + const link = reactive(useLink(props)); + const { options } = inject(routerKey); + const elClass = computed(() => ({ + [getLinkClass(props.activeClass, options.linkActiveClass, 'router-link-active')]: link.isActive, + // [getLinkClass( + // props.inactiveClass, + // options.linkInactiveClass, + // 'router-link-inactive' + // )]: !link.isExactActive, + [getLinkClass(props.exactActiveClass, options.linkExactActiveClass, 'router-link-exact-active')]: link.isExactActive, + })); + return () => { + const children = slots.default && slots.default(link); + return props.custom + ? children + : h('a', { + 'aria-current': link.isExactActive + ? props.ariaCurrentValue + : null, + href: link.href, + // this would override user added attrs but Vue will still add + // the listener, so we end up triggering both + onClick: link.navigate, + class: elClass.value, + }, children); + }; + }, +}); +// export the public type for h/tsx inference +// also to avoid inline import() in generated d.ts files +/** + * Component to render a link that triggers a navigation on click. + */ +const RouterLink = RouterLinkImpl; +function guardEvent(e) { + // don't redirect with control keys + if (e.metaKey || e.altKey || e.ctrlKey || e.shiftKey) + return; + // don't redirect when preventDefault called + if (e.defaultPrevented) + return; + // don't redirect on right click + if (e.button !== undefined && e.button !== 0) + return; + // don't redirect if `target="_blank"` + // @ts-expect-error getAttribute does exist + if (e.currentTarget && e.currentTarget.getAttribute) { + // @ts-expect-error getAttribute exists + const target = e.currentTarget.getAttribute('target'); + if (/\b_blank\b/i.test(target)) + return; + } + // this may be a Weex event which doesn't have this method + if (e.preventDefault) + e.preventDefault(); + return true; +} +function includesParams(outer, inner) { + for (const key in inner) { + const innerValue = inner[key]; + const outerValue = outer[key]; + if (typeof innerValue === 'string') { + if (innerValue !== outerValue) + return false; + } + else { + if (!isArray(outerValue) || + outerValue.length !== innerValue.length || + innerValue.some((value, i) => value !== outerValue[i])) + return false; + } + } + return true; +} +/** + * Get the original path value of a record by following its aliasOf + * @param record + */ +function getOriginalPath(record) { + return record ? (record.aliasOf ? record.aliasOf.path : record.path) : ''; +} +/** + * Utility class to get the active class based on defaults. + * @param propClass + * @param globalClass + * @param defaultClass + */ +const getLinkClass = (propClass, globalClass, defaultClass) => propClass != null + ? propClass + : globalClass != null + ? globalClass + : defaultClass; + +const RouterViewImpl = /*#__PURE__*/ defineComponent({ + name: 'RouterView', + // #674 we manually inherit them + inheritAttrs: false, + props: { + name: { + type: String, + default: 'default', + }, + route: Object, + }, + // Better compat for @vue/compat users + // https://github.com/vuejs/router/issues/1315 + compatConfig: { MODE: 3 }, + setup(props, { attrs, slots }) { + warnDeprecatedUsage(); + const injectedRoute = inject(routerViewLocationKey); + const routeToDisplay = computed(() => props.route || injectedRoute.value); + const injectedDepth = inject(viewDepthKey, 0); + // The depth changes based on empty components option, which allows passthrough routes e.g. routes with children + // that are used to reuse the `path` property + const depth = computed(() => { + let initialDepth = unref(injectedDepth); + const { matched } = routeToDisplay.value; + let matchedRoute; + while ((matchedRoute = matched[initialDepth]) && + !matchedRoute.components) { + initialDepth++; + } + return initialDepth; + }); + const matchedRouteRef = computed(() => routeToDisplay.value.matched[depth.value]); + provide(viewDepthKey, computed(() => depth.value + 1)); + provide(matchedRouteKey, matchedRouteRef); + provide(routerViewLocationKey, routeToDisplay); + const viewRef = ref(); + // watch at the same time the component instance, the route record we are + // rendering, and the name + watch(() => [viewRef.value, matchedRouteRef.value, props.name], ([instance, to, name], [oldInstance, from, oldName]) => { + // copy reused instances + if (to) { + // this will update the instance for new instances as well as reused + // instances when navigating to a new route + to.instances[name] = instance; + // the component instance is reused for a different route or name, so + // we copy any saved update or leave guards. With async setup, the + // mounting component will mount before the matchedRoute changes, + // making instance === oldInstance, so we check if guards have been + // added before. This works because we remove guards when + // unmounting/deactivating components + if (from && from !== to && instance && instance === oldInstance) { + if (!to.leaveGuards.size) { + to.leaveGuards = from.leaveGuards; + } + if (!to.updateGuards.size) { + to.updateGuards = from.updateGuards; + } + } + } + // trigger beforeRouteEnter next callbacks + if (instance && + to && + // if there is no instance but to and from are the same this might be + // the first visit + (!from || !isSameRouteRecord(to, from) || !oldInstance)) { + (to.enterCallbacks[name] || []).forEach(callback => callback(instance)); + } + }, { flush: 'post' }); + return () => { + const route = routeToDisplay.value; + // we need the value at the time we render because when we unmount, we + // navigated to a different location so the value is different + const currentName = props.name; + const matchedRoute = matchedRouteRef.value; + const ViewComponent = matchedRoute && matchedRoute.components[currentName]; + if (!ViewComponent) { + return normalizeSlot(slots.default, { Component: ViewComponent, route }); + } + // props from route configuration + const routePropsOption = matchedRoute.props[currentName]; + const routeProps = routePropsOption + ? routePropsOption === true + ? route.params + : typeof routePropsOption === 'function' + ? routePropsOption(route) + : routePropsOption + : null; + const onVnodeUnmounted = vnode => { + // remove the instance reference to prevent leak + if (vnode.component.isUnmounted) { + matchedRoute.instances[currentName] = null; + } + }; + const component = h(ViewComponent, assign({}, routeProps, attrs, { + onVnodeUnmounted, + ref: viewRef, + })); + if (isBrowser && + component.ref) { + // TODO: can display if it's an alias, its props + const info = { + depth: depth.value, + name: matchedRoute.name, + path: matchedRoute.path, + meta: matchedRoute.meta, + }; + const internalInstances = isArray(component.ref) + ? component.ref.map(r => r.i) + : [component.ref.i]; + internalInstances.forEach(instance => { + // @ts-expect-error + instance.__vrv_devtools = info; + }); + } + return ( + // pass the vnode to the slot as a prop. + // h and both accept vnodes + normalizeSlot(slots.default, { Component: component, route }) || + component); + }; + }, +}); +function normalizeSlot(slot, data) { + if (!slot) + return null; + const slotContent = slot(data); + return slotContent.length === 1 ? slotContent[0] : slotContent; +} +// export the public type for h/tsx inference +// also to avoid inline import() in generated d.ts files +/** + * Component to display the current route the user is at. + */ +const RouterView = RouterViewImpl; +// warn against deprecated usage with & +// due to functional component being no longer eager in Vue 3 +function warnDeprecatedUsage() { + const instance = getCurrentInstance(); + const parentName = instance.parent && instance.parent.type.name; + const parentSubTreeType = instance.parent && instance.parent.subTree && instance.parent.subTree.type; + if (parentName && + (parentName === 'KeepAlive' || parentName.includes('Transition')) && + typeof parentSubTreeType === 'object' && + parentSubTreeType.name === 'RouterView') { + const comp = parentName === 'KeepAlive' ? 'keep-alive' : 'transition'; + warn(` can no longer be used directly inside or .\n` + + `Use slot props instead:\n\n` + + `\n` + + ` <${comp}>\n` + + ` \n` + + ` \n` + + ``); + } +} + +/** + * Copies a route location and removes any problematic properties that cannot be shown in devtools (e.g. Vue instances). + * + * @param routeLocation - routeLocation to format + * @param tooltip - optional tooltip + * @returns a copy of the routeLocation + */ +function formatRouteLocation(routeLocation, tooltip) { + const copy = assign({}, routeLocation, { + // remove variables that can contain vue instances + matched: routeLocation.matched.map(matched => omit(matched, ['instances', 'children', 'aliasOf'])), + }); + return { + _custom: { + type: null, + readOnly: true, + display: routeLocation.fullPath, + tooltip, + value: copy, + }, + }; +} +function formatDisplay(display) { + return { + _custom: { + display, + }, + }; +} +// to support multiple router instances +let routerId = 0; +function addDevtools(app, router, matcher) { + // Take over router.beforeEach and afterEach + // make sure we are not registering the devtool twice + if (router.__hasDevtools) + return; + router.__hasDevtools = true; + // increment to support multiple router instances + const id = routerId++; + setupDevtoolsPlugin({ + id: 'org.vuejs.router' + (id ? '.' + id : ''), + label: 'Vue Router', + packageName: 'vue-router', + homepage: 'https://router.vuejs.org', + logo: 'https://router.vuejs.org/logo.png', + componentStateTypes: ['Routing'], + app, + }, api => { + if (typeof api.now !== 'function') { + console.warn('[Vue Router]: You seem to be using an outdated version of Vue Devtools. Are you still using the Beta release instead of the stable one? You can find the links at https://devtools.vuejs.org/guide/installation.html.'); + } + // display state added by the router + api.on.inspectComponent((payload, ctx) => { + if (payload.instanceData) { + payload.instanceData.state.push({ + type: 'Routing', + key: '$route', + editable: false, + value: formatRouteLocation(router.currentRoute.value, 'Current Route'), + }); + } + }); + // mark router-link as active and display tags on router views + api.on.visitComponentTree(({ treeNode: node, componentInstance }) => { + if (componentInstance.__vrv_devtools) { + const info = componentInstance.__vrv_devtools; + node.tags.push({ + label: (info.name ? `${info.name.toString()}: ` : '') + info.path, + textColor: 0, + tooltip: 'This component is rendered by <router-view>', + backgroundColor: PINK_500, + }); + } + // if multiple useLink are used + if (isArray(componentInstance.__vrl_devtools)) { + componentInstance.__devtoolsApi = api; + componentInstance.__vrl_devtools.forEach(devtoolsData => { + let backgroundColor = ORANGE_400; + let tooltip = ''; + if (devtoolsData.isExactActive) { + backgroundColor = LIME_500; + tooltip = 'This is exactly active'; + } + else if (devtoolsData.isActive) { + backgroundColor = BLUE_600; + tooltip = 'This link is active'; + } + node.tags.push({ + label: devtoolsData.route.path, + textColor: 0, + tooltip, + backgroundColor, + }); + }); + } + }); + watch(router.currentRoute, () => { + // refresh active state + refreshRoutesView(); + api.notifyComponentUpdate(); + api.sendInspectorTree(routerInspectorId); + api.sendInspectorState(routerInspectorId); + }); + const navigationsLayerId = 'router:navigations:' + id; + api.addTimelineLayer({ + id: navigationsLayerId, + label: `Router${id ? ' ' + id : ''} Navigations`, + color: 0x40a8c4, + }); + // const errorsLayerId = 'router:errors' + // api.addTimelineLayer({ + // id: errorsLayerId, + // label: 'Router Errors', + // color: 0xea5455, + // }) + router.onError((error, to) => { + api.addTimelineEvent({ + layerId: navigationsLayerId, + event: { + title: 'Error during Navigation', + subtitle: to.fullPath, + logType: 'error', + time: api.now(), + data: { error }, + groupId: to.meta.__navigationId, + }, + }); + }); + // attached to `meta` and used to group events + let navigationId = 0; + router.beforeEach((to, from) => { + const data = { + guard: formatDisplay('beforeEach'), + from: formatRouteLocation(from, 'Current Location during this navigation'), + to: formatRouteLocation(to, 'Target location'), + }; + // Used to group navigations together, hide from devtools + Object.defineProperty(to.meta, '__navigationId', { + value: navigationId++, + }); + api.addTimelineEvent({ + layerId: navigationsLayerId, + event: { + time: api.now(), + title: 'Start of navigation', + subtitle: to.fullPath, + data, + groupId: to.meta.__navigationId, + }, + }); + }); + router.afterEach((to, from, failure) => { + const data = { + guard: formatDisplay('afterEach'), + }; + if (failure) { + data.failure = { + _custom: { + type: Error, + readOnly: true, + display: failure ? failure.message : '', + tooltip: 'Navigation Failure', + value: failure, + }, + }; + data.status = formatDisplay('âŒ'); + } + else { + data.status = formatDisplay('✅'); + } + // we set here to have the right order + data.from = formatRouteLocation(from, 'Current Location during this navigation'); + data.to = formatRouteLocation(to, 'Target location'); + api.addTimelineEvent({ + layerId: navigationsLayerId, + event: { + title: 'End of navigation', + subtitle: to.fullPath, + time: api.now(), + data, + logType: failure ? 'warning' : 'default', + groupId: to.meta.__navigationId, + }, + }); + }); + /** + * Inspector of Existing routes + */ + const routerInspectorId = 'router-inspector:' + id; + api.addInspector({ + id: routerInspectorId, + label: 'Routes' + (id ? ' ' + id : ''), + icon: 'book', + treeFilterPlaceholder: 'Search routes', + }); + function refreshRoutesView() { + // the routes view isn't active + if (!activeRoutesPayload) + return; + const payload = activeRoutesPayload; + // children routes will appear as nested + let routes = matcher.getRoutes().filter(route => !route.parent || + // these routes have a parent with no component which will not appear in the view + // therefore we still need to include them + !route.parent.record.components); + // reset match state to false + routes.forEach(resetMatchStateOnRouteRecord); + // apply a match state if there is a payload + if (payload.filter) { + routes = routes.filter(route => + // save matches state based on the payload + isRouteMatching(route, payload.filter.toLowerCase())); + } + // mark active routes + routes.forEach(route => markRouteRecordActive(route, router.currentRoute.value)); + payload.rootNodes = routes.map(formatRouteRecordForInspector); + } + let activeRoutesPayload; + api.on.getInspectorTree(payload => { + activeRoutesPayload = payload; + if (payload.app === app && payload.inspectorId === routerInspectorId) { + refreshRoutesView(); + } + }); + /** + * Display information about the currently selected route record + */ + api.on.getInspectorState(payload => { + if (payload.app === app && payload.inspectorId === routerInspectorId) { + const routes = matcher.getRoutes(); + const route = routes.find(route => route.record.__vd_id === payload.nodeId); + if (route) { + payload.state = { + options: formatRouteRecordMatcherForStateInspector(route), + }; + } + } + }); + api.sendInspectorTree(routerInspectorId); + api.sendInspectorState(routerInspectorId); + }); +} +function modifierForKey(key) { + if (key.optional) { + return key.repeatable ? '*' : '?'; + } + else { + return key.repeatable ? '+' : ''; + } +} +function formatRouteRecordMatcherForStateInspector(route) { + const { record } = route; + const fields = [ + { editable: false, key: 'path', value: record.path }, + ]; + if (record.name != null) { + fields.push({ + editable: false, + key: 'name', + value: record.name, + }); + } + fields.push({ editable: false, key: 'regexp', value: route.re }); + if (route.keys.length) { + fields.push({ + editable: false, + key: 'keys', + value: { + _custom: { + type: null, + readOnly: true, + display: route.keys + .map(key => `${key.name}${modifierForKey(key)}`) + .join(' '), + tooltip: 'Param keys', + value: route.keys, + }, + }, + }); + } + if (record.redirect != null) { + fields.push({ + editable: false, + key: 'redirect', + value: record.redirect, + }); + } + if (route.alias.length) { + fields.push({ + editable: false, + key: 'aliases', + value: route.alias.map(alias => alias.record.path), + }); + } + if (Object.keys(route.record.meta).length) { + fields.push({ + editable: false, + key: 'meta', + value: route.record.meta, + }); + } + fields.push({ + key: 'score', + editable: false, + value: { + _custom: { + type: null, + readOnly: true, + display: route.score.map(score => score.join(', ')).join(' | '), + tooltip: 'Score used to sort routes', + value: route.score, + }, + }, + }); + return fields; +} +/** + * Extracted from tailwind palette + */ +const PINK_500 = 0xec4899; +const BLUE_600 = 0x2563eb; +const LIME_500 = 0x84cc16; +const CYAN_400 = 0x22d3ee; +const ORANGE_400 = 0xfb923c; +// const GRAY_100 = 0xf4f4f5 +const DARK = 0x666666; +function formatRouteRecordForInspector(route) { + const tags = []; + const { record } = route; + if (record.name != null) { + tags.push({ + label: String(record.name), + textColor: 0, + backgroundColor: CYAN_400, + }); + } + if (record.aliasOf) { + tags.push({ + label: 'alias', + textColor: 0, + backgroundColor: ORANGE_400, + }); + } + if (route.__vd_match) { + tags.push({ + label: 'matches', + textColor: 0, + backgroundColor: PINK_500, + }); + } + if (route.__vd_exactActive) { + tags.push({ + label: 'exact', + textColor: 0, + backgroundColor: LIME_500, + }); + } + if (route.__vd_active) { + tags.push({ + label: 'active', + textColor: 0, + backgroundColor: BLUE_600, + }); + } + if (record.redirect) { + tags.push({ + label: typeof record.redirect === 'string' + ? `redirect: ${record.redirect}` + : 'redirects', + textColor: 0xffffff, + backgroundColor: DARK, + }); + } + // add an id to be able to select it. Using the `path` is not possible because + // empty path children would collide with their parents + let id = record.__vd_id; + if (id == null) { + id = String(routeRecordId++); + record.__vd_id = id; + } + return { + id, + label: record.path, + tags, + children: route.children.map(formatRouteRecordForInspector), + }; +} +// incremental id for route records and inspector state +let routeRecordId = 0; +const EXTRACT_REGEXP_RE = /^\/(.*)\/([a-z]*)$/; +function markRouteRecordActive(route, currentRoute) { + // no route will be active if matched is empty + // reset the matching state + const isExactActive = currentRoute.matched.length && + isSameRouteRecord(currentRoute.matched[currentRoute.matched.length - 1], route.record); + route.__vd_exactActive = route.__vd_active = isExactActive; + if (!isExactActive) { + route.__vd_active = currentRoute.matched.some(match => isSameRouteRecord(match, route.record)); + } + route.children.forEach(childRoute => markRouteRecordActive(childRoute, currentRoute)); +} +function resetMatchStateOnRouteRecord(route) { + route.__vd_match = false; + route.children.forEach(resetMatchStateOnRouteRecord); +} +function isRouteMatching(route, filter) { + const found = String(route.re).match(EXTRACT_REGEXP_RE); + route.__vd_match = false; + if (!found || found.length < 3) { + return false; + } + // use a regexp without $ at the end to match nested routes better + const nonEndingRE = new RegExp(found[1].replace(/\$$/, ''), found[2]); + if (nonEndingRE.test(filter)) { + // mark children as matches + route.children.forEach(child => isRouteMatching(child, filter)); + // exception case: `/` + if (route.record.path !== '/' || filter === '/') { + route.__vd_match = route.re.test(filter); + return true; + } + // hide the / route + return false; + } + const path = route.record.path.toLowerCase(); + const decodedPath = decode(path); + // also allow partial matching on the path + if (!filter.startsWith('/') && + (decodedPath.includes(filter) || path.includes(filter))) + return true; + if (decodedPath.startsWith(filter) || path.startsWith(filter)) + return true; + if (route.record.name && String(route.record.name).includes(filter)) + return true; + return route.children.some(child => isRouteMatching(child, filter)); +} +function omit(obj, keys) { + const ret = {}; + for (const key in obj) { + if (!keys.includes(key)) { + // @ts-expect-error + ret[key] = obj[key]; + } + } + return ret; +} + +/** + * Creates a Router instance that can be used by a Vue app. + * + * @param options - {@link RouterOptions} + */ +function createRouter(options) { + const matcher = createRouterMatcher(options.routes, options); + const parseQuery$1 = options.parseQuery || parseQuery; + const stringifyQuery$1 = options.stringifyQuery || stringifyQuery; + const routerHistory = options.history; + if (!routerHistory) + throw new Error('Provide the "history" option when calling "createRouter()":' + + ' https://next.router.vuejs.org/api/#history.'); + const beforeGuards = useCallbacks(); + const beforeResolveGuards = useCallbacks(); + const afterGuards = useCallbacks(); + const currentRoute = shallowRef(START_LOCATION_NORMALIZED); + let pendingLocation = START_LOCATION_NORMALIZED; + // leave the scrollRestoration if no scrollBehavior is provided + if (isBrowser && options.scrollBehavior && 'scrollRestoration' in history) { + history.scrollRestoration = 'manual'; + } + const normalizeParams = applyToParams.bind(null, paramValue => '' + paramValue); + const encodeParams = applyToParams.bind(null, encodeParam); + const decodeParams = + // @ts-expect-error: intentionally avoid the type check + applyToParams.bind(null, decode); + function addRoute(parentOrRoute, route) { + let parent; + let record; + if (isRouteName(parentOrRoute)) { + parent = matcher.getRecordMatcher(parentOrRoute); + record = route; + } + else { + record = parentOrRoute; + } + return matcher.addRoute(record, parent); + } + function removeRoute(name) { + const recordMatcher = matcher.getRecordMatcher(name); + if (recordMatcher) { + matcher.removeRoute(recordMatcher); + } + else { + warn(`Cannot remove non-existent route "${String(name)}"`); + } + } + function getRoutes() { + return matcher.getRoutes().map(routeMatcher => routeMatcher.record); + } + function hasRoute(name) { + return !!matcher.getRecordMatcher(name); + } + function resolve(rawLocation, currentLocation) { + // const objectLocation = routerLocationAsObject(rawLocation) + // we create a copy to modify it later + currentLocation = assign({}, currentLocation || currentRoute.value); + if (typeof rawLocation === 'string') { + const locationNormalized = parseURL(parseQuery$1, rawLocation, currentLocation.path); + const matchedRoute = matcher.resolve({ path: locationNormalized.path }, currentLocation); + const href = routerHistory.createHref(locationNormalized.fullPath); + { + if (href.startsWith('//')) + warn(`Location "${rawLocation}" resolved to "${href}". A resolved location cannot start with multiple slashes.`); + else if (!matchedRoute.matched.length) { + warn(`No match found for location with path "${rawLocation}"`); + } + } + // locationNormalized is always a new object + return assign(locationNormalized, matchedRoute, { + params: decodeParams(matchedRoute.params), + hash: decode(locationNormalized.hash), + redirectedFrom: undefined, + href, + }); + } + let matcherLocation; + // path could be relative in object as well + if ('path' in rawLocation) { + if ('params' in rawLocation && + !('name' in rawLocation) && + // @ts-expect-error: the type is never + Object.keys(rawLocation.params).length) { + warn(`Path "${rawLocation.path}" was passed with params but they will be ignored. Use a named route alongside params instead.`); + } + matcherLocation = assign({}, rawLocation, { + path: parseURL(parseQuery$1, rawLocation.path, currentLocation.path).path, + }); + } + else { + // remove any nullish param + const targetParams = assign({}, rawLocation.params); + for (const key in targetParams) { + if (targetParams[key] == null) { + delete targetParams[key]; + } + } + // pass encoded values to the matcher, so it can produce encoded path and fullPath + matcherLocation = assign({}, rawLocation, { + params: encodeParams(targetParams), + }); + // current location params are decoded, we need to encode them in case the + // matcher merges the params + currentLocation.params = encodeParams(currentLocation.params); + } + const matchedRoute = matcher.resolve(matcherLocation, currentLocation); + const hash = rawLocation.hash || ''; + if (hash && !hash.startsWith('#')) { + warn(`A \`hash\` should always start with the character "#". Replace "${hash}" with "#${hash}".`); + } + // the matcher might have merged current location params, so + // we need to run the decoding again + matchedRoute.params = normalizeParams(decodeParams(matchedRoute.params)); + const fullPath = stringifyURL(stringifyQuery$1, assign({}, rawLocation, { + hash: encodeHash(hash), + path: matchedRoute.path, + })); + const href = routerHistory.createHref(fullPath); + { + if (href.startsWith('//')) { + warn(`Location "${rawLocation}" resolved to "${href}". A resolved location cannot start with multiple slashes.`); + } + else if (!matchedRoute.matched.length) { + warn(`No match found for location with path "${'path' in rawLocation ? rawLocation.path : rawLocation}"`); + } + } + return assign({ + fullPath, + // keep the hash encoded so fullPath is effectively path + encodedQuery + + // hash + hash, + query: + // if the user is using a custom query lib like qs, we might have + // nested objects, so we keep the query as is, meaning it can contain + // numbers at `$route.query`, but at the point, the user will have to + // use their own type anyway. + // https://github.com/vuejs/router/issues/328#issuecomment-649481567 + stringifyQuery$1 === stringifyQuery + ? normalizeQuery(rawLocation.query) + : (rawLocation.query || {}), + }, matchedRoute, { + redirectedFrom: undefined, + href, + }); + } + function locationAsObject(to) { + return typeof to === 'string' + ? parseURL(parseQuery$1, to, currentRoute.value.path) + : assign({}, to); + } + function checkCanceledNavigation(to, from) { + if (pendingLocation !== to) { + return createRouterError(8 /* ErrorTypes.NAVIGATION_CANCELLED */, { + from, + to, + }); + } + } + function push(to) { + return pushWithRedirect(to); + } + function replace(to) { + return push(assign(locationAsObject(to), { replace: true })); + } + function handleRedirectRecord(to) { + const lastMatched = to.matched[to.matched.length - 1]; + if (lastMatched && lastMatched.redirect) { + const { redirect } = lastMatched; + let newTargetLocation = typeof redirect === 'function' ? redirect(to) : redirect; + if (typeof newTargetLocation === 'string') { + newTargetLocation = + newTargetLocation.includes('?') || newTargetLocation.includes('#') + ? (newTargetLocation = locationAsObject(newTargetLocation)) + : // force empty params + { path: newTargetLocation }; + // @ts-expect-error: force empty params when a string is passed to let + // the router parse them again + newTargetLocation.params = {}; + } + if (!('path' in newTargetLocation) && + !('name' in newTargetLocation)) { + warn(`Invalid redirect found:\n${JSON.stringify(newTargetLocation, null, 2)}\n when navigating to "${to.fullPath}". A redirect must contain a name or path. This will break in production.`); + throw new Error('Invalid redirect'); + } + return assign({ + query: to.query, + hash: to.hash, + // avoid transferring params if the redirect has a path + params: 'path' in newTargetLocation ? {} : to.params, + }, newTargetLocation); + } + } + function pushWithRedirect(to, redirectedFrom) { + const targetLocation = (pendingLocation = resolve(to)); + const from = currentRoute.value; + const data = to.state; + const force = to.force; + // to could be a string where `replace` is a function + const replace = to.replace === true; + const shouldRedirect = handleRedirectRecord(targetLocation); + if (shouldRedirect) + return pushWithRedirect(assign(locationAsObject(shouldRedirect), { + state: typeof shouldRedirect === 'object' + ? assign({}, data, shouldRedirect.state) + : data, + force, + replace, + }), + // keep original redirectedFrom if it exists + redirectedFrom || targetLocation); + // if it was a redirect we already called `pushWithRedirect` above + const toLocation = targetLocation; + toLocation.redirectedFrom = redirectedFrom; + let failure; + if (!force && isSameRouteLocation(stringifyQuery$1, from, targetLocation)) { + failure = createRouterError(16 /* ErrorTypes.NAVIGATION_DUPLICATED */, { to: toLocation, from }); + // trigger scroll to allow scrolling to the same anchor + handleScroll(from, from, + // this is a push, the only way for it to be triggered from a + // history.listen is with a redirect, which makes it become a push + true, + // This cannot be the first navigation because the initial location + // cannot be manually navigated to + false); + } + return (failure ? Promise.resolve(failure) : navigate(toLocation, from)) + .catch((error) => isNavigationFailure(error) + ? // navigation redirects still mark the router as ready + isNavigationFailure(error, 2 /* ErrorTypes.NAVIGATION_GUARD_REDIRECT */) + ? error + : markAsReady(error) // also returns the error + : // reject any unknown error + triggerError(error, toLocation, from)) + .then((failure) => { + if (failure) { + if (isNavigationFailure(failure, 2 /* ErrorTypes.NAVIGATION_GUARD_REDIRECT */)) { + if (// we are redirecting to the same location we were already at + isSameRouteLocation(stringifyQuery$1, resolve(failure.to), toLocation) && + // and we have done it a couple of times + redirectedFrom && + // @ts-expect-error: added only in dev + (redirectedFrom._count = redirectedFrom._count + ? // @ts-expect-error + redirectedFrom._count + 1 + : 1) > 30) { + warn(`Detected a possibly infinite redirection in a navigation guard when going from "${from.fullPath}" to "${toLocation.fullPath}". Aborting to avoid a Stack Overflow.\n Are you always returning a new location within a navigation guard? That would lead to this error. Only return when redirecting or aborting, that should fix this. This might break in production if not fixed.`); + return Promise.reject(new Error('Infinite redirect in navigation guard')); + } + return pushWithRedirect( + // keep options + assign({ + // preserve an existing replacement but allow the redirect to override it + replace, + }, locationAsObject(failure.to), { + state: typeof failure.to === 'object' + ? assign({}, data, failure.to.state) + : data, + force, + }), + // preserve the original redirectedFrom if any + redirectedFrom || toLocation); + } + } + else { + // if we fail we don't finalize the navigation + failure = finalizeNavigation(toLocation, from, true, replace, data); + } + triggerAfterEach(toLocation, from, failure); + return failure; + }); + } + /** + * Helper to reject and skip all navigation guards if a new navigation happened + * @param to + * @param from + */ + function checkCanceledNavigationAndReject(to, from) { + const error = checkCanceledNavigation(to, from); + return error ? Promise.reject(error) : Promise.resolve(); + } + function runWithContext(fn) { + const app = installedApps.values().next().value; + // support Vue < 3.3 + return app && typeof app.runWithContext === 'function' + ? app.runWithContext(fn) + : fn(); + } + // TODO: refactor the whole before guards by internally using router.beforeEach + function navigate(to, from) { + let guards; + const [leavingRecords, updatingRecords, enteringRecords] = extractChangingRecords(to, from); + // all components here have been resolved once because we are leaving + guards = extractComponentsGuards(leavingRecords.reverse(), 'beforeRouteLeave', to, from); + // leavingRecords is already reversed + for (const record of leavingRecords) { + record.leaveGuards.forEach(guard => { + guards.push(guardToPromiseFn(guard, to, from)); + }); + } + const canceledNavigationCheck = checkCanceledNavigationAndReject.bind(null, to, from); + guards.push(canceledNavigationCheck); + // run the queue of per route beforeRouteLeave guards + return (runGuardQueue(guards) + .then(() => { + // check global guards beforeEach + guards = []; + for (const guard of beforeGuards.list()) { + guards.push(guardToPromiseFn(guard, to, from)); + } + guards.push(canceledNavigationCheck); + return runGuardQueue(guards); + }) + .then(() => { + // check in components beforeRouteUpdate + guards = extractComponentsGuards(updatingRecords, 'beforeRouteUpdate', to, from); + for (const record of updatingRecords) { + record.updateGuards.forEach(guard => { + guards.push(guardToPromiseFn(guard, to, from)); + }); + } + guards.push(canceledNavigationCheck); + // run the queue of per route beforeEnter guards + return runGuardQueue(guards); + }) + .then(() => { + // check the route beforeEnter + guards = []; + for (const record of enteringRecords) { + // do not trigger beforeEnter on reused views + if (record.beforeEnter) { + if (isArray(record.beforeEnter)) { + for (const beforeEnter of record.beforeEnter) + guards.push(guardToPromiseFn(beforeEnter, to, from)); + } + else { + guards.push(guardToPromiseFn(record.beforeEnter, to, from)); + } + } + } + guards.push(canceledNavigationCheck); + // run the queue of per route beforeEnter guards + return runGuardQueue(guards); + }) + .then(() => { + // NOTE: at this point to.matched is normalized and does not contain any () => Promise + // clear existing enterCallbacks, these are added by extractComponentsGuards + to.matched.forEach(record => (record.enterCallbacks = {})); + // check in-component beforeRouteEnter + guards = extractComponentsGuards(enteringRecords, 'beforeRouteEnter', to, from); + guards.push(canceledNavigationCheck); + // run the queue of per route beforeEnter guards + return runGuardQueue(guards); + }) + .then(() => { + // check global guards beforeResolve + guards = []; + for (const guard of beforeResolveGuards.list()) { + guards.push(guardToPromiseFn(guard, to, from)); + } + guards.push(canceledNavigationCheck); + return runGuardQueue(guards); + }) + // catch any navigation canceled + .catch(err => isNavigationFailure(err, 8 /* ErrorTypes.NAVIGATION_CANCELLED */) + ? err + : Promise.reject(err))); + } + function triggerAfterEach(to, from, failure) { + // navigation is confirmed, call afterGuards + // TODO: wrap with error handlers + afterGuards + .list() + .forEach(guard => runWithContext(() => guard(to, from, failure))); + } + /** + * - Cleans up any navigation guards + * - Changes the url if necessary + * - Calls the scrollBehavior + */ + function finalizeNavigation(toLocation, from, isPush, replace, data) { + // a more recent navigation took place + const error = checkCanceledNavigation(toLocation, from); + if (error) + return error; + // only consider as push if it's not the first navigation + const isFirstNavigation = from === START_LOCATION_NORMALIZED; + const state = !isBrowser ? {} : history.state; + // change URL only if the user did a push/replace and if it's not the initial navigation because + // it's just reflecting the url + if (isPush) { + // on the initial navigation, we want to reuse the scroll position from + // history state if it exists + if (replace || isFirstNavigation) + routerHistory.replace(toLocation.fullPath, assign({ + scroll: isFirstNavigation && state && state.scroll, + }, data)); + else + routerHistory.push(toLocation.fullPath, data); + } + // accept current navigation + currentRoute.value = toLocation; + handleScroll(toLocation, from, isPush, isFirstNavigation); + markAsReady(); + } + let removeHistoryListener; + // attach listener to history to trigger navigations + function setupListeners() { + // avoid setting up listeners twice due to an invalid first navigation + if (removeHistoryListener) + return; + removeHistoryListener = routerHistory.listen((to, _from, info) => { + if (!router.listening) + return; + // cannot be a redirect route because it was in history + const toLocation = resolve(to); + // due to dynamic routing, and to hash history with manual navigation + // (manually changing the url or calling history.hash = '#/somewhere'), + // there could be a redirect record in history + const shouldRedirect = handleRedirectRecord(toLocation); + if (shouldRedirect) { + pushWithRedirect(assign(shouldRedirect, { replace: true }), toLocation).catch(noop); + return; + } + pendingLocation = toLocation; + const from = currentRoute.value; + // TODO: should be moved to web history? + if (isBrowser) { + saveScrollPosition(getScrollKey(from.fullPath, info.delta), computeScrollPosition()); + } + navigate(toLocation, from) + .catch((error) => { + if (isNavigationFailure(error, 4 /* ErrorTypes.NAVIGATION_ABORTED */ | 8 /* ErrorTypes.NAVIGATION_CANCELLED */)) { + return error; + } + if (isNavigationFailure(error, 2 /* ErrorTypes.NAVIGATION_GUARD_REDIRECT */)) { + // Here we could call if (info.delta) routerHistory.go(-info.delta, + // false) but this is bug prone as we have no way to wait the + // navigation to be finished before calling pushWithRedirect. Using + // a setTimeout of 16ms seems to work but there is no guarantee for + // it to work on every browser. So instead we do not restore the + // history entry and trigger a new navigation as requested by the + // navigation guard. + // the error is already handled by router.push we just want to avoid + // logging the error + pushWithRedirect(error.to, toLocation + // avoid an uncaught rejection, let push call triggerError + ) + .then(failure => { + // manual change in hash history #916 ending up in the URL not + // changing, but it was changed by the manual url change, so we + // need to manually change it ourselves + if (isNavigationFailure(failure, 4 /* ErrorTypes.NAVIGATION_ABORTED */ | + 16 /* ErrorTypes.NAVIGATION_DUPLICATED */) && + !info.delta && + info.type === NavigationType.pop) { + routerHistory.go(-1, false); + } + }) + .catch(noop); + // avoid the then branch + return Promise.reject(); + } + // do not restore history on unknown direction + if (info.delta) { + routerHistory.go(-info.delta, false); + } + // unrecognized error, transfer to the global handler + return triggerError(error, toLocation, from); + }) + .then((failure) => { + failure = + failure || + finalizeNavigation( + // after navigation, all matched components are resolved + toLocation, from, false); + // revert the navigation + if (failure) { + if (info.delta && + // a new navigation has been triggered, so we do not want to revert, that will change the current history + // entry while a different route is displayed + !isNavigationFailure(failure, 8 /* ErrorTypes.NAVIGATION_CANCELLED */)) { + routerHistory.go(-info.delta, false); + } + else if (info.type === NavigationType.pop && + isNavigationFailure(failure, 4 /* ErrorTypes.NAVIGATION_ABORTED */ | 16 /* ErrorTypes.NAVIGATION_DUPLICATED */)) { + // manual change in hash history #916 + // it's like a push but lacks the information of the direction + routerHistory.go(-1, false); + } + } + triggerAfterEach(toLocation, from, failure); + }) + // avoid warnings in the console about uncaught rejections, they are logged by triggerErrors + .catch(noop); + }); + } + // Initialization and Errors + let readyHandlers = useCallbacks(); + let errorListeners = useCallbacks(); + let ready; + /** + * Trigger errorListeners added via onError and throws the error as well + * + * @param error - error to throw + * @param to - location we were navigating to when the error happened + * @param from - location we were navigating from when the error happened + * @returns the error as a rejected promise + */ + function triggerError(error, to, from) { + markAsReady(error); + const list = errorListeners.list(); + if (list.length) { + list.forEach(handler => handler(error, to, from)); + } + else { + { + warn('uncaught error during route navigation:'); + } + console.error(error); + } + // reject the error no matter there were error listeners or not + return Promise.reject(error); + } + function isReady() { + if (ready && currentRoute.value !== START_LOCATION_NORMALIZED) + return Promise.resolve(); + return new Promise((resolve, reject) => { + readyHandlers.add([resolve, reject]); + }); + } + function markAsReady(err) { + if (!ready) { + // still not ready if an error happened + ready = !err; + setupListeners(); + readyHandlers + .list() + .forEach(([resolve, reject]) => (err ? reject(err) : resolve())); + readyHandlers.reset(); + } + return err; + } + // Scroll behavior + function handleScroll(to, from, isPush, isFirstNavigation) { + const { scrollBehavior } = options; + if (!isBrowser || !scrollBehavior) + return Promise.resolve(); + const scrollPosition = (!isPush && getSavedScrollPosition(getScrollKey(to.fullPath, 0))) || + ((isFirstNavigation || !isPush) && + history.state && + history.state.scroll) || + null; + return nextTick() + .then(() => scrollBehavior(to, from, scrollPosition)) + .then(position => position && scrollToPosition(position)) + .catch(err => triggerError(err, to, from)); + } + const go = (delta) => routerHistory.go(delta); + let started; + const installedApps = new Set(); + const router = { + currentRoute, + listening: true, + addRoute, + removeRoute, + hasRoute, + getRoutes, + resolve, + options, + push, + replace, + go, + back: () => go(-1), + forward: () => go(1), + beforeEach: beforeGuards.add, + beforeResolve: beforeResolveGuards.add, + afterEach: afterGuards.add, + onError: errorListeners.add, + isReady, + install(app) { + const router = this; + app.component('RouterLink', RouterLink); + app.component('RouterView', RouterView); + app.config.globalProperties.$router = router; + Object.defineProperty(app.config.globalProperties, '$route', { + enumerable: true, + get: () => unref(currentRoute), + }); + // this initial navigation is only necessary on client, on server it doesn't + // make sense because it will create an extra unnecessary navigation and could + // lead to problems + if (isBrowser && + // used for the initial navigation client side to avoid pushing + // multiple times when the router is used in multiple apps + !started && + currentRoute.value === START_LOCATION_NORMALIZED) { + // see above + started = true; + push(routerHistory.location).catch(err => { + warn('Unexpected error when starting the router:', err); + }); + } + const reactiveRoute = {}; + for (const key in START_LOCATION_NORMALIZED) { + Object.defineProperty(reactiveRoute, key, { + get: () => currentRoute.value[key], + enumerable: true, + }); + } + app.provide(routerKey, router); + app.provide(routeLocationKey, shallowReactive(reactiveRoute)); + app.provide(routerViewLocationKey, currentRoute); + const unmountApp = app.unmount; + installedApps.add(app); + app.unmount = function () { + installedApps.delete(app); + // the router is not attached to an app anymore + if (installedApps.size < 1) { + // invalidate the current navigation + pendingLocation = START_LOCATION_NORMALIZED; + removeHistoryListener && removeHistoryListener(); + removeHistoryListener = null; + currentRoute.value = START_LOCATION_NORMALIZED; + started = false; + ready = false; + } + unmountApp(); + }; + // TODO: this probably needs to be updated so it can be used by vue-termui + if (isBrowser) { + addDevtools(app, router, matcher); + } + }, + }; + // TODO: type this as NavigationGuardReturn or similar instead of any + function runGuardQueue(guards) { + return guards.reduce((promise, guard) => promise.then(() => runWithContext(guard)), Promise.resolve()); + } + return router; +} +function extractChangingRecords(to, from) { + const leavingRecords = []; + const updatingRecords = []; + const enteringRecords = []; + const len = Math.max(from.matched.length, to.matched.length); + for (let i = 0; i < len; i++) { + const recordFrom = from.matched[i]; + if (recordFrom) { + if (to.matched.find(record => isSameRouteRecord(record, recordFrom))) + updatingRecords.push(recordFrom); + else + leavingRecords.push(recordFrom); + } + const recordTo = to.matched[i]; + if (recordTo) { + // the type doesn't matter because we are comparing per reference + if (!from.matched.find(record => isSameRouteRecord(record, recordTo))) { + enteringRecords.push(recordTo); + } + } + } + return [leavingRecords, updatingRecords, enteringRecords]; +} + +/** + * Returns the router instance. Equivalent to using `$router` inside + * templates. + */ +function useRouter() { + return inject(routerKey); +} +/** + * Returns the current route location. Equivalent to using `$route` inside + * templates. + */ +function useRoute() { + return inject(routeLocationKey); +} + +export { NavigationFailureType, RouterLink, RouterView, START_LOCATION_NORMALIZED as START_LOCATION, createMemoryHistory, createRouter, createRouterMatcher, createWebHashHistory, createWebHistory, isNavigationFailure, loadRouteLocation, matchedRouteKey, onBeforeRouteLeave, onBeforeRouteUpdate, parseQuery, routeLocationKey, routerKey, routerViewLocationKey, stringifyQuery, useLink, useRoute, useRouter, viewDepthKey }; \ No newline at end of file diff --git a/hal-core/resources/web/js/vue/vue.esm-browser.js b/hal-core/resources/web/js/vue/vue.esm-browser.js new file mode 100644 index 00000000..5f8d6664 --- /dev/null +++ b/hal-core/resources/web/js/vue/vue.esm-browser.js @@ -0,0 +1,16633 @@ +/** +* vue v3.4.15 +* (c) 2018-present Yuxi (Evan) You and Vue contributors +* @license MIT +**/ +function makeMap(str, expectsLowerCase) { + const set = new Set(str.split(",")); + return expectsLowerCase ? (val) => set.has(val.toLowerCase()) : (val) => set.has(val); +} + +const EMPTY_OBJ = Object.freeze({}) ; +const EMPTY_ARR = Object.freeze([]) ; +const NOOP = () => { +}; +const NO = () => false; +const isOn = (key) => key.charCodeAt(0) === 111 && key.charCodeAt(1) === 110 && // uppercase letter +(key.charCodeAt(2) > 122 || key.charCodeAt(2) < 97); +const isModelListener = (key) => key.startsWith("onUpdate:"); +const extend = Object.assign; +const remove = (arr, el) => { + const i = arr.indexOf(el); + if (i > -1) { + arr.splice(i, 1); + } +}; +const hasOwnProperty$1 = Object.prototype.hasOwnProperty; +const hasOwn = (val, key) => hasOwnProperty$1.call(val, key); +const isArray = Array.isArray; +const isMap = (val) => toTypeString(val) === "[object Map]"; +const isSet = (val) => toTypeString(val) === "[object Set]"; +const isDate = (val) => toTypeString(val) === "[object Date]"; +const isRegExp = (val) => toTypeString(val) === "[object RegExp]"; +const isFunction = (val) => typeof val === "function"; +const isString = (val) => typeof val === "string"; +const isSymbol = (val) => typeof val === "symbol"; +const isObject = (val) => val !== null && typeof val === "object"; +const isPromise = (val) => { + return (isObject(val) || isFunction(val)) && isFunction(val.then) && isFunction(val.catch); +}; +const objectToString = Object.prototype.toString; +const toTypeString = (value) => objectToString.call(value); +const toRawType = (value) => { + return toTypeString(value).slice(8, -1); +}; +const isPlainObject = (val) => toTypeString(val) === "[object Object]"; +const isIntegerKey = (key) => isString(key) && key !== "NaN" && key[0] !== "-" && "" + parseInt(key, 10) === key; +const isReservedProp = /* @__PURE__ */ makeMap( + // the leading comma is intentional so empty string "" is also included + ",key,ref,ref_for,ref_key,onVnodeBeforeMount,onVnodeMounted,onVnodeBeforeUpdate,onVnodeUpdated,onVnodeBeforeUnmount,onVnodeUnmounted" +); +const isBuiltInDirective = /* @__PURE__ */ makeMap( + "bind,cloak,else-if,else,for,html,if,model,on,once,pre,show,slot,text,memo" +); +const cacheStringFunction = (fn) => { + const cache = /* @__PURE__ */ Object.create(null); + return (str) => { + const hit = cache[str]; + return hit || (cache[str] = fn(str)); + }; +}; +const camelizeRE = /-(\w)/g; +const camelize = cacheStringFunction((str) => { + return str.replace(camelizeRE, (_, c) => c ? c.toUpperCase() : ""); +}); +const hyphenateRE = /\B([A-Z])/g; +const hyphenate = cacheStringFunction( + (str) => str.replace(hyphenateRE, "-$1").toLowerCase() +); +const capitalize = cacheStringFunction((str) => { + return str.charAt(0).toUpperCase() + str.slice(1); +}); +const toHandlerKey = cacheStringFunction((str) => { + const s = str ? `on${capitalize(str)}` : ``; + return s; +}); +const hasChanged = (value, oldValue) => !Object.is(value, oldValue); +const invokeArrayFns = (fns, arg) => { + for (let i = 0; i < fns.length; i++) { + fns[i](arg); + } +}; +const def = (obj, key, value) => { + Object.defineProperty(obj, key, { + configurable: true, + enumerable: false, + value + }); +}; +const looseToNumber = (val) => { + const n = parseFloat(val); + return isNaN(n) ? val : n; +}; +const toNumber = (val) => { + const n = isString(val) ? Number(val) : NaN; + return isNaN(n) ? val : n; +}; +let _globalThis; +const getGlobalThis = () => { + return _globalThis || (_globalThis = typeof globalThis !== "undefined" ? globalThis : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : typeof global !== "undefined" ? global : {}); +}; + +const PatchFlagNames = { + [1]: `TEXT`, + [2]: `CLASS`, + [4]: `STYLE`, + [8]: `PROPS`, + [16]: `FULL_PROPS`, + [32]: `NEED_HYDRATION`, + [64]: `STABLE_FRAGMENT`, + [128]: `KEYED_FRAGMENT`, + [256]: `UNKEYED_FRAGMENT`, + [512]: `NEED_PATCH`, + [1024]: `DYNAMIC_SLOTS`, + [2048]: `DEV_ROOT_FRAGMENT`, + [-1]: `HOISTED`, + [-2]: `BAIL` +}; + +const slotFlagsText = { + [1]: "STABLE", + [2]: "DYNAMIC", + [3]: "FORWARDED" +}; + +const GLOBALS_ALLOWED = "Infinity,undefined,NaN,isFinite,isNaN,parseFloat,parseInt,decodeURI,decodeURIComponent,encodeURI,encodeURIComponent,Math,Number,Date,Array,Object,Boolean,String,RegExp,Map,Set,JSON,Intl,BigInt,console,Error"; +const isGloballyAllowed = /* @__PURE__ */ makeMap(GLOBALS_ALLOWED); + +const range = 2; +function generateCodeFrame(source, start = 0, end = source.length) { + let lines = source.split(/(\r?\n)/); + const newlineSequences = lines.filter((_, idx) => idx % 2 === 1); + lines = lines.filter((_, idx) => idx % 2 === 0); + let count = 0; + const res = []; + for (let i = 0; i < lines.length; i++) { + count += lines[i].length + (newlineSequences[i] && newlineSequences[i].length || 0); + if (count >= start) { + for (let j = i - range; j <= i + range || end > count; j++) { + if (j < 0 || j >= lines.length) + continue; + const line = j + 1; + res.push( + `${line}${" ".repeat(Math.max(3 - String(line).length, 0))}| ${lines[j]}` + ); + const lineLength = lines[j].length; + const newLineSeqLength = newlineSequences[j] && newlineSequences[j].length || 0; + if (j === i) { + const pad = start - (count - (lineLength + newLineSeqLength)); + const length = Math.max( + 1, + end > count ? lineLength - pad : end - start + ); + res.push(` | ` + " ".repeat(pad) + "^".repeat(length)); + } else if (j > i) { + if (end > count) { + const length = Math.max(Math.min(end - count, lineLength), 1); + res.push(` | ` + "^".repeat(length)); + } + count += lineLength + newLineSeqLength; + } + } + break; + } + } + return res.join("\n"); +} + +function normalizeStyle(value) { + if (isArray(value)) { + const res = {}; + for (let i = 0; i < value.length; i++) { + const item = value[i]; + const normalized = isString(item) ? parseStringStyle(item) : normalizeStyle(item); + if (normalized) { + for (const key in normalized) { + res[key] = normalized[key]; + } + } + } + return res; + } else if (isString(value) || isObject(value)) { + return value; + } +} +const listDelimiterRE = /;(?![^(]*\))/g; +const propertyDelimiterRE = /:([^]+)/; +const styleCommentRE = /\/\*[^]*?\*\//g; +function parseStringStyle(cssText) { + const ret = {}; + cssText.replace(styleCommentRE, "").split(listDelimiterRE).forEach((item) => { + if (item) { + const tmp = item.split(propertyDelimiterRE); + tmp.length > 1 && (ret[tmp[0].trim()] = tmp[1].trim()); + } + }); + return ret; +} +function stringifyStyle(styles) { + let ret = ""; + if (!styles || isString(styles)) { + return ret; + } + for (const key in styles) { + const value = styles[key]; + const normalizedKey = key.startsWith(`--`) ? key : hyphenate(key); + if (isString(value) || typeof value === "number") { + ret += `${normalizedKey}:${value};`; + } + } + return ret; +} +function normalizeClass(value) { + let res = ""; + if (isString(value)) { + res = value; + } else if (isArray(value)) { + for (let i = 0; i < value.length; i++) { + const normalized = normalizeClass(value[i]); + if (normalized) { + res += normalized + " "; + } + } + } else if (isObject(value)) { + for (const name in value) { + if (value[name]) { + res += name + " "; + } + } + } + return res.trim(); +} +function normalizeProps(props) { + if (!props) + return null; + let { class: klass, style } = props; + if (klass && !isString(klass)) { + props.class = normalizeClass(klass); + } + if (style) { + props.style = normalizeStyle(style); + } + return props; +} + +const HTML_TAGS = "html,body,base,head,link,meta,style,title,address,article,aside,footer,header,hgroup,h1,h2,h3,h4,h5,h6,nav,section,div,dd,dl,dt,figcaption,figure,picture,hr,img,li,main,ol,p,pre,ul,a,b,abbr,bdi,bdo,br,cite,code,data,dfn,em,i,kbd,mark,q,rp,rt,ruby,s,samp,small,span,strong,sub,sup,time,u,var,wbr,area,audio,map,track,video,embed,object,param,source,canvas,script,noscript,del,ins,caption,col,colgroup,table,thead,tbody,td,th,tr,button,datalist,fieldset,form,input,label,legend,meter,optgroup,option,output,progress,select,textarea,details,dialog,menu,summary,template,blockquote,iframe,tfoot"; +const SVG_TAGS = "svg,animate,animateMotion,animateTransform,circle,clipPath,color-profile,defs,desc,discard,ellipse,feBlend,feColorMatrix,feComponentTransfer,feComposite,feConvolveMatrix,feDiffuseLighting,feDisplacementMap,feDistantLight,feDropShadow,feFlood,feFuncA,feFuncB,feFuncG,feFuncR,feGaussianBlur,feImage,feMerge,feMergeNode,feMorphology,feOffset,fePointLight,feSpecularLighting,feSpotLight,feTile,feTurbulence,filter,foreignObject,g,hatch,hatchpath,image,line,linearGradient,marker,mask,mesh,meshgradient,meshpatch,meshrow,metadata,mpath,path,pattern,polygon,polyline,radialGradient,rect,set,solidcolor,stop,switch,symbol,text,textPath,title,tspan,unknown,use,view"; +const MATH_TAGS = "annotation,annotation-xml,maction,maligngroup,malignmark,math,menclose,merror,mfenced,mfrac,mfraction,mglyph,mi,mlabeledtr,mlongdiv,mmultiscripts,mn,mo,mover,mpadded,mphantom,mprescripts,mroot,mrow,ms,mscarries,mscarry,msgroup,msline,mspace,msqrt,msrow,mstack,mstyle,msub,msubsup,msup,mtable,mtd,mtext,mtr,munder,munderover,none,semantics"; +const VOID_TAGS = "area,base,br,col,embed,hr,img,input,link,meta,param,source,track,wbr"; +const isHTMLTag = /* @__PURE__ */ makeMap(HTML_TAGS); +const isSVGTag = /* @__PURE__ */ makeMap(SVG_TAGS); +const isMathMLTag = /* @__PURE__ */ makeMap(MATH_TAGS); +const isVoidTag = /* @__PURE__ */ makeMap(VOID_TAGS); + +const specialBooleanAttrs = `itemscope,allowfullscreen,formnovalidate,ismap,nomodule,novalidate,readonly`; +const isSpecialBooleanAttr = /* @__PURE__ */ makeMap(specialBooleanAttrs); +const isBooleanAttr = /* @__PURE__ */ makeMap( + specialBooleanAttrs + `,async,autofocus,autoplay,controls,default,defer,disabled,hidden,inert,loop,open,required,reversed,scoped,seamless,checked,muted,multiple,selected` +); +function includeBooleanAttr(value) { + return !!value || value === ""; +} +const isKnownHtmlAttr = /* @__PURE__ */ makeMap( + `accept,accept-charset,accesskey,action,align,allow,alt,async,autocapitalize,autocomplete,autofocus,autoplay,background,bgcolor,border,buffered,capture,challenge,charset,checked,cite,class,code,codebase,color,cols,colspan,content,contenteditable,contextmenu,controls,coords,crossorigin,csp,data,datetime,decoding,default,defer,dir,dirname,disabled,download,draggable,dropzone,enctype,enterkeyhint,for,form,formaction,formenctype,formmethod,formnovalidate,formtarget,headers,height,hidden,high,href,hreflang,http-equiv,icon,id,importance,inert,integrity,ismap,itemprop,keytype,kind,label,lang,language,loading,list,loop,low,manifest,max,maxlength,minlength,media,min,multiple,muted,name,novalidate,open,optimum,pattern,ping,placeholder,poster,preload,radiogroup,readonly,referrerpolicy,rel,required,reversed,rows,rowspan,sandbox,scope,scoped,selected,shape,size,sizes,slot,span,spellcheck,src,srcdoc,srclang,srcset,start,step,style,summary,tabindex,target,title,translate,type,usemap,value,width,wrap` +); +const isKnownSvgAttr = /* @__PURE__ */ makeMap( + `xmlns,accent-height,accumulate,additive,alignment-baseline,alphabetic,amplitude,arabic-form,ascent,attributeName,attributeType,azimuth,baseFrequency,baseline-shift,baseProfile,bbox,begin,bias,by,calcMode,cap-height,class,clip,clipPathUnits,clip-path,clip-rule,color,color-interpolation,color-interpolation-filters,color-profile,color-rendering,contentScriptType,contentStyleType,crossorigin,cursor,cx,cy,d,decelerate,descent,diffuseConstant,direction,display,divisor,dominant-baseline,dur,dx,dy,edgeMode,elevation,enable-background,end,exponent,fill,fill-opacity,fill-rule,filter,filterRes,filterUnits,flood-color,flood-opacity,font-family,font-size,font-size-adjust,font-stretch,font-style,font-variant,font-weight,format,from,fr,fx,fy,g1,g2,glyph-name,glyph-orientation-horizontal,glyph-orientation-vertical,glyphRef,gradientTransform,gradientUnits,hanging,height,href,hreflang,horiz-adv-x,horiz-origin-x,id,ideographic,image-rendering,in,in2,intercept,k,k1,k2,k3,k4,kernelMatrix,kernelUnitLength,kerning,keyPoints,keySplines,keyTimes,lang,lengthAdjust,letter-spacing,lighting-color,limitingConeAngle,local,marker-end,marker-mid,marker-start,markerHeight,markerUnits,markerWidth,mask,maskContentUnits,maskUnits,mathematical,max,media,method,min,mode,name,numOctaves,offset,opacity,operator,order,orient,orientation,origin,overflow,overline-position,overline-thickness,panose-1,paint-order,path,pathLength,patternContentUnits,patternTransform,patternUnits,ping,pointer-events,points,pointsAtX,pointsAtY,pointsAtZ,preserveAlpha,preserveAspectRatio,primitiveUnits,r,radius,referrerPolicy,refX,refY,rel,rendering-intent,repeatCount,repeatDur,requiredExtensions,requiredFeatures,restart,result,rotate,rx,ry,scale,seed,shape-rendering,slope,spacing,specularConstant,specularExponent,speed,spreadMethod,startOffset,stdDeviation,stemh,stemv,stitchTiles,stop-color,stop-opacity,strikethrough-position,strikethrough-thickness,string,stroke,stroke-dasharray,stroke-dashoffset,stroke-linecap,stroke-linejoin,stroke-miterlimit,stroke-opacity,stroke-width,style,surfaceScale,systemLanguage,tabindex,tableValues,target,targetX,targetY,text-anchor,text-decoration,text-rendering,textLength,to,transform,transform-origin,type,u1,u2,underline-position,underline-thickness,unicode,unicode-bidi,unicode-range,units-per-em,v-alphabetic,v-hanging,v-ideographic,v-mathematical,values,vector-effect,version,vert-adv-y,vert-origin-x,vert-origin-y,viewBox,viewTarget,visibility,width,widths,word-spacing,writing-mode,x,x-height,x1,x2,xChannelSelector,xlink:actuate,xlink:arcrole,xlink:href,xlink:role,xlink:show,xlink:title,xlink:type,xmlns:xlink,xml:base,xml:lang,xml:space,y,y1,y2,yChannelSelector,z,zoomAndPan` +); +function isRenderableAttrValue(value) { + if (value == null) { + return false; + } + const type = typeof value; + return type === "string" || type === "number" || type === "boolean"; +} + +function looseCompareArrays(a, b) { + if (a.length !== b.length) + return false; + let equal = true; + for (let i = 0; equal && i < a.length; i++) { + equal = looseEqual(a[i], b[i]); + } + return equal; +} +function looseEqual(a, b) { + if (a === b) + return true; + let aValidType = isDate(a); + let bValidType = isDate(b); + if (aValidType || bValidType) { + return aValidType && bValidType ? a.getTime() === b.getTime() : false; + } + aValidType = isSymbol(a); + bValidType = isSymbol(b); + if (aValidType || bValidType) { + return a === b; + } + aValidType = isArray(a); + bValidType = isArray(b); + if (aValidType || bValidType) { + return aValidType && bValidType ? looseCompareArrays(a, b) : false; + } + aValidType = isObject(a); + bValidType = isObject(b); + if (aValidType || bValidType) { + if (!aValidType || !bValidType) { + return false; + } + const aKeysCount = Object.keys(a).length; + const bKeysCount = Object.keys(b).length; + if (aKeysCount !== bKeysCount) { + return false; + } + for (const key in a) { + const aHasKey = a.hasOwnProperty(key); + const bHasKey = b.hasOwnProperty(key); + if (aHasKey && !bHasKey || !aHasKey && bHasKey || !looseEqual(a[key], b[key])) { + return false; + } + } + } + return String(a) === String(b); +} +function looseIndexOf(arr, val) { + return arr.findIndex((item) => looseEqual(item, val)); +} + +const toDisplayString = (val) => { + return isString(val) ? val : val == null ? "" : isArray(val) || isObject(val) && (val.toString === objectToString || !isFunction(val.toString)) ? JSON.stringify(val, replacer, 2) : String(val); +}; +const replacer = (_key, val) => { + if (val && val.__v_isRef) { + return replacer(_key, val.value); + } else if (isMap(val)) { + return { + [`Map(${val.size})`]: [...val.entries()].reduce( + (entries, [key, val2], i) => { + entries[stringifySymbol(key, i) + " =>"] = val2; + return entries; + }, + {} + ) + }; + } else if (isSet(val)) { + return { + [`Set(${val.size})`]: [...val.values()].map((v) => stringifySymbol(v)) + }; + } else if (isSymbol(val)) { + return stringifySymbol(val); + } else if (isObject(val) && !isArray(val) && !isPlainObject(val)) { + return String(val); + } + return val; +}; +const stringifySymbol = (v, i = "") => { + var _a; + return isSymbol(v) ? `Symbol(${(_a = v.description) != null ? _a : i})` : v; +}; + +function warn$2(msg, ...args) { + console.warn(`[Vue warn] ${msg}`, ...args); +} + +let activeEffectScope; +class EffectScope { + constructor(detached = false) { + this.detached = detached; + /** + * @internal + */ + this._active = true; + /** + * @internal + */ + this.effects = []; + /** + * @internal + */ + this.cleanups = []; + this.parent = activeEffectScope; + if (!detached && activeEffectScope) { + this.index = (activeEffectScope.scopes || (activeEffectScope.scopes = [])).push( + this + ) - 1; + } + } + get active() { + return this._active; + } + run(fn) { + if (this._active) { + const currentEffectScope = activeEffectScope; + try { + activeEffectScope = this; + return fn(); + } finally { + activeEffectScope = currentEffectScope; + } + } else { + warn$2(`cannot run an inactive effect scope.`); + } + } + /** + * This should only be called on non-detached scopes + * @internal + */ + on() { + activeEffectScope = this; + } + /** + * This should only be called on non-detached scopes + * @internal + */ + off() { + activeEffectScope = this.parent; + } + stop(fromParent) { + if (this._active) { + let i, l; + for (i = 0, l = this.effects.length; i < l; i++) { + this.effects[i].stop(); + } + for (i = 0, l = this.cleanups.length; i < l; i++) { + this.cleanups[i](); + } + if (this.scopes) { + for (i = 0, l = this.scopes.length; i < l; i++) { + this.scopes[i].stop(true); + } + } + if (!this.detached && this.parent && !fromParent) { + const last = this.parent.scopes.pop(); + if (last && last !== this) { + this.parent.scopes[this.index] = last; + last.index = this.index; + } + } + this.parent = void 0; + this._active = false; + } + } +} +function effectScope(detached) { + return new EffectScope(detached); +} +function recordEffectScope(effect, scope = activeEffectScope) { + if (scope && scope.active) { + scope.effects.push(effect); + } +} +function getCurrentScope() { + return activeEffectScope; +} +function onScopeDispose(fn) { + if (activeEffectScope) { + activeEffectScope.cleanups.push(fn); + } else { + warn$2( + `onScopeDispose() is called when there is no active effect scope to be associated with.` + ); + } +} + +let activeEffect; +class ReactiveEffect { + constructor(fn, trigger, scheduler, scope) { + this.fn = fn; + this.trigger = trigger; + this.scheduler = scheduler; + this.active = true; + this.deps = []; + /** + * @internal + */ + this._dirtyLevel = 2; + /** + * @internal + */ + this._trackId = 0; + /** + * @internal + */ + this._runnings = 0; + /** + * @internal + */ + this._shouldSchedule = false; + /** + * @internal + */ + this._depsLength = 0; + recordEffectScope(this, scope); + } + get dirty() { + if (this._dirtyLevel === 1) { + pauseTracking(); + for (let i = 0; i < this._depsLength; i++) { + const dep = this.deps[i]; + if (dep.computed) { + triggerComputed(dep.computed); + if (this._dirtyLevel >= 2) { + break; + } + } + } + if (this._dirtyLevel < 2) { + this._dirtyLevel = 0; + } + resetTracking(); + } + return this._dirtyLevel >= 2; + } + set dirty(v) { + this._dirtyLevel = v ? 2 : 0; + } + run() { + this._dirtyLevel = 0; + if (!this.active) { + return this.fn(); + } + let lastShouldTrack = shouldTrack; + let lastEffect = activeEffect; + try { + shouldTrack = true; + activeEffect = this; + this._runnings++; + preCleanupEffect(this); + return this.fn(); + } finally { + postCleanupEffect(this); + this._runnings--; + activeEffect = lastEffect; + shouldTrack = lastShouldTrack; + } + } + stop() { + var _a; + if (this.active) { + preCleanupEffect(this); + postCleanupEffect(this); + (_a = this.onStop) == null ? void 0 : _a.call(this); + this.active = false; + } + } +} +function triggerComputed(computed) { + return computed.value; +} +function preCleanupEffect(effect2) { + effect2._trackId++; + effect2._depsLength = 0; +} +function postCleanupEffect(effect2) { + if (effect2.deps && effect2.deps.length > effect2._depsLength) { + for (let i = effect2._depsLength; i < effect2.deps.length; i++) { + cleanupDepEffect(effect2.deps[i], effect2); + } + effect2.deps.length = effect2._depsLength; + } +} +function cleanupDepEffect(dep, effect2) { + const trackId = dep.get(effect2); + if (trackId !== void 0 && effect2._trackId !== trackId) { + dep.delete(effect2); + if (dep.size === 0) { + dep.cleanup(); + } + } +} +function effect(fn, options) { + if (fn.effect instanceof ReactiveEffect) { + fn = fn.effect.fn; + } + const _effect = new ReactiveEffect(fn, NOOP, () => { + if (_effect.dirty) { + _effect.run(); + } + }); + if (options) { + extend(_effect, options); + if (options.scope) + recordEffectScope(_effect, options.scope); + } + if (!options || !options.lazy) { + _effect.run(); + } + const runner = _effect.run.bind(_effect); + runner.effect = _effect; + return runner; +} +function stop(runner) { + runner.effect.stop(); +} +let shouldTrack = true; +let pauseScheduleStack = 0; +const trackStack = []; +function pauseTracking() { + trackStack.push(shouldTrack); + shouldTrack = false; +} +function resetTracking() { + const last = trackStack.pop(); + shouldTrack = last === void 0 ? true : last; +} +function pauseScheduling() { + pauseScheduleStack++; +} +function resetScheduling() { + pauseScheduleStack--; + while (!pauseScheduleStack && queueEffectSchedulers.length) { + queueEffectSchedulers.shift()(); + } +} +function trackEffect(effect2, dep, debuggerEventExtraInfo) { + var _a; + if (dep.get(effect2) !== effect2._trackId) { + dep.set(effect2, effect2._trackId); + const oldDep = effect2.deps[effect2._depsLength]; + if (oldDep !== dep) { + if (oldDep) { + cleanupDepEffect(oldDep, effect2); + } + effect2.deps[effect2._depsLength++] = dep; + } else { + effect2._depsLength++; + } + { + (_a = effect2.onTrack) == null ? void 0 : _a.call(effect2, extend({ effect: effect2 }, debuggerEventExtraInfo)); + } + } +} +const queueEffectSchedulers = []; +function triggerEffects(dep, dirtyLevel, debuggerEventExtraInfo) { + var _a; + pauseScheduling(); + for (const effect2 of dep.keys()) { + if (effect2._dirtyLevel < dirtyLevel && dep.get(effect2) === effect2._trackId) { + const lastDirtyLevel = effect2._dirtyLevel; + effect2._dirtyLevel = dirtyLevel; + if (lastDirtyLevel === 0) { + effect2._shouldSchedule = true; + { + (_a = effect2.onTrigger) == null ? void 0 : _a.call(effect2, extend({ effect: effect2 }, debuggerEventExtraInfo)); + } + effect2.trigger(); + } + } + } + scheduleEffects(dep); + resetScheduling(); +} +function scheduleEffects(dep) { + for (const effect2 of dep.keys()) { + if (effect2.scheduler && effect2._shouldSchedule && (!effect2._runnings || effect2.allowRecurse) && dep.get(effect2) === effect2._trackId) { + effect2._shouldSchedule = false; + queueEffectSchedulers.push(effect2.scheduler); + } + } +} + +const createDep = (cleanup, computed) => { + const dep = /* @__PURE__ */ new Map(); + dep.cleanup = cleanup; + dep.computed = computed; + return dep; +}; + +const targetMap = /* @__PURE__ */ new WeakMap(); +const ITERATE_KEY = Symbol("iterate" ); +const MAP_KEY_ITERATE_KEY = Symbol("Map key iterate" ); +function track(target, type, key) { + if (shouldTrack && activeEffect) { + let depsMap = targetMap.get(target); + if (!depsMap) { + targetMap.set(target, depsMap = /* @__PURE__ */ new Map()); + } + let dep = depsMap.get(key); + if (!dep) { + depsMap.set(key, dep = createDep(() => depsMap.delete(key))); + } + trackEffect( + activeEffect, + dep, + { + target, + type, + key + } + ); + } +} +function trigger(target, type, key, newValue, oldValue, oldTarget) { + const depsMap = targetMap.get(target); + if (!depsMap) { + return; + } + let deps = []; + if (type === "clear") { + deps = [...depsMap.values()]; + } else if (key === "length" && isArray(target)) { + const newLength = Number(newValue); + depsMap.forEach((dep, key2) => { + if (key2 === "length" || !isSymbol(key2) && key2 >= newLength) { + deps.push(dep); + } + }); + } else { + if (key !== void 0) { + deps.push(depsMap.get(key)); + } + switch (type) { + case "add": + if (!isArray(target)) { + deps.push(depsMap.get(ITERATE_KEY)); + if (isMap(target)) { + deps.push(depsMap.get(MAP_KEY_ITERATE_KEY)); + } + } else if (isIntegerKey(key)) { + deps.push(depsMap.get("length")); + } + break; + case "delete": + if (!isArray(target)) { + deps.push(depsMap.get(ITERATE_KEY)); + if (isMap(target)) { + deps.push(depsMap.get(MAP_KEY_ITERATE_KEY)); + } + } + break; + case "set": + if (isMap(target)) { + deps.push(depsMap.get(ITERATE_KEY)); + } + break; + } + } + pauseScheduling(); + for (const dep of deps) { + if (dep) { + triggerEffects( + dep, + 2, + { + target, + type, + key, + newValue, + oldValue, + oldTarget + } + ); + } + } + resetScheduling(); +} +function getDepFromReactive(object, key) { + var _a; + return (_a = targetMap.get(object)) == null ? void 0 : _a.get(key); +} + +const isNonTrackableKeys = /* @__PURE__ */ makeMap(`__proto__,__v_isRef,__isVue`); +const builtInSymbols = new Set( + /* @__PURE__ */ Object.getOwnPropertyNames(Symbol).filter((key) => key !== "arguments" && key !== "caller").map((key) => Symbol[key]).filter(isSymbol) +); +const arrayInstrumentations = /* @__PURE__ */ createArrayInstrumentations(); +function createArrayInstrumentations() { + const instrumentations = {}; + ["includes", "indexOf", "lastIndexOf"].forEach((key) => { + instrumentations[key] = function(...args) { + const arr = toRaw(this); + for (let i = 0, l = this.length; i < l; i++) { + track(arr, "get", i + ""); + } + const res = arr[key](...args); + if (res === -1 || res === false) { + return arr[key](...args.map(toRaw)); + } else { + return res; + } + }; + }); + ["push", "pop", "shift", "unshift", "splice"].forEach((key) => { + instrumentations[key] = function(...args) { + pauseTracking(); + pauseScheduling(); + const res = toRaw(this)[key].apply(this, args); + resetScheduling(); + resetTracking(); + return res; + }; + }); + return instrumentations; +} +function hasOwnProperty(key) { + const obj = toRaw(this); + track(obj, "has", key); + return obj.hasOwnProperty(key); +} +class BaseReactiveHandler { + constructor(_isReadonly = false, _shallow = false) { + this._isReadonly = _isReadonly; + this._shallow = _shallow; + } + get(target, key, receiver) { + const isReadonly2 = this._isReadonly, shallow = this._shallow; + if (key === "__v_isReactive") { + return !isReadonly2; + } else if (key === "__v_isReadonly") { + return isReadonly2; + } else if (key === "__v_isShallow") { + return shallow; + } else if (key === "__v_raw") { + if (receiver === (isReadonly2 ? shallow ? shallowReadonlyMap : readonlyMap : shallow ? shallowReactiveMap : reactiveMap).get(target) || // receiver is not the reactive proxy, but has the same prototype + // this means the reciever is a user proxy of the reactive proxy + Object.getPrototypeOf(target) === Object.getPrototypeOf(receiver)) { + return target; + } + return; + } + const targetIsArray = isArray(target); + if (!isReadonly2) { + if (targetIsArray && hasOwn(arrayInstrumentations, key)) { + return Reflect.get(arrayInstrumentations, key, receiver); + } + if (key === "hasOwnProperty") { + return hasOwnProperty; + } + } + const res = Reflect.get(target, key, receiver); + if (isSymbol(key) ? builtInSymbols.has(key) : isNonTrackableKeys(key)) { + return res; + } + if (!isReadonly2) { + track(target, "get", key); + } + if (shallow) { + return res; + } + if (isRef(res)) { + return targetIsArray && isIntegerKey(key) ? res : res.value; + } + if (isObject(res)) { + return isReadonly2 ? readonly(res) : reactive(res); + } + return res; + } +} +class MutableReactiveHandler extends BaseReactiveHandler { + constructor(shallow = false) { + super(false, shallow); + } + set(target, key, value, receiver) { + let oldValue = target[key]; + if (!this._shallow) { + const isOldValueReadonly = isReadonly(oldValue); + if (!isShallow(value) && !isReadonly(value)) { + oldValue = toRaw(oldValue); + value = toRaw(value); + } + if (!isArray(target) && isRef(oldValue) && !isRef(value)) { + if (isOldValueReadonly) { + return false; + } else { + oldValue.value = value; + return true; + } + } + } + const hadKey = isArray(target) && isIntegerKey(key) ? Number(key) < target.length : hasOwn(target, key); + const result = Reflect.set(target, key, value, receiver); + if (target === toRaw(receiver)) { + if (!hadKey) { + trigger(target, "add", key, value); + } else if (hasChanged(value, oldValue)) { + trigger(target, "set", key, value, oldValue); + } + } + return result; + } + deleteProperty(target, key) { + const hadKey = hasOwn(target, key); + const oldValue = target[key]; + const result = Reflect.deleteProperty(target, key); + if (result && hadKey) { + trigger(target, "delete", key, void 0, oldValue); + } + return result; + } + has(target, key) { + const result = Reflect.has(target, key); + if (!isSymbol(key) || !builtInSymbols.has(key)) { + track(target, "has", key); + } + return result; + } + ownKeys(target) { + track( + target, + "iterate", + isArray(target) ? "length" : ITERATE_KEY + ); + return Reflect.ownKeys(target); + } +} +class ReadonlyReactiveHandler extends BaseReactiveHandler { + constructor(shallow = false) { + super(true, shallow); + } + set(target, key) { + { + warn$2( + `Set operation on key "${String(key)}" failed: target is readonly.`, + target + ); + } + return true; + } + deleteProperty(target, key) { + { + warn$2( + `Delete operation on key "${String(key)}" failed: target is readonly.`, + target + ); + } + return true; + } +} +const mutableHandlers = /* @__PURE__ */ new MutableReactiveHandler(); +const readonlyHandlers = /* @__PURE__ */ new ReadonlyReactiveHandler(); +const shallowReactiveHandlers = /* @__PURE__ */ new MutableReactiveHandler( + true +); +const shallowReadonlyHandlers = /* @__PURE__ */ new ReadonlyReactiveHandler(true); + +const toShallow = (value) => value; +const getProto = (v) => Reflect.getPrototypeOf(v); +function get(target, key, isReadonly = false, isShallow = false) { + target = target["__v_raw"]; + const rawTarget = toRaw(target); + const rawKey = toRaw(key); + if (!isReadonly) { + if (hasChanged(key, rawKey)) { + track(rawTarget, "get", key); + } + track(rawTarget, "get", rawKey); + } + const { has: has2 } = getProto(rawTarget); + const wrap = isShallow ? toShallow : isReadonly ? toReadonly : toReactive; + if (has2.call(rawTarget, key)) { + return wrap(target.get(key)); + } else if (has2.call(rawTarget, rawKey)) { + return wrap(target.get(rawKey)); + } else if (target !== rawTarget) { + target.get(key); + } +} +function has(key, isReadonly = false) { + const target = this["__v_raw"]; + const rawTarget = toRaw(target); + const rawKey = toRaw(key); + if (!isReadonly) { + if (hasChanged(key, rawKey)) { + track(rawTarget, "has", key); + } + track(rawTarget, "has", rawKey); + } + return key === rawKey ? target.has(key) : target.has(key) || target.has(rawKey); +} +function size(target, isReadonly = false) { + target = target["__v_raw"]; + !isReadonly && track(toRaw(target), "iterate", ITERATE_KEY); + return Reflect.get(target, "size", target); +} +function add(value) { + value = toRaw(value); + const target = toRaw(this); + const proto = getProto(target); + const hadKey = proto.has.call(target, value); + if (!hadKey) { + target.add(value); + trigger(target, "add", value, value); + } + return this; +} +function set(key, value) { + value = toRaw(value); + const target = toRaw(this); + const { has: has2, get: get2 } = getProto(target); + let hadKey = has2.call(target, key); + if (!hadKey) { + key = toRaw(key); + hadKey = has2.call(target, key); + } else { + checkIdentityKeys(target, has2, key); + } + const oldValue = get2.call(target, key); + target.set(key, value); + if (!hadKey) { + trigger(target, "add", key, value); + } else if (hasChanged(value, oldValue)) { + trigger(target, "set", key, value, oldValue); + } + return this; +} +function deleteEntry(key) { + const target = toRaw(this); + const { has: has2, get: get2 } = getProto(target); + let hadKey = has2.call(target, key); + if (!hadKey) { + key = toRaw(key); + hadKey = has2.call(target, key); + } else { + checkIdentityKeys(target, has2, key); + } + const oldValue = get2 ? get2.call(target, key) : void 0; + const result = target.delete(key); + if (hadKey) { + trigger(target, "delete", key, void 0, oldValue); + } + return result; +} +function clear() { + const target = toRaw(this); + const hadItems = target.size !== 0; + const oldTarget = isMap(target) ? new Map(target) : new Set(target) ; + const result = target.clear(); + if (hadItems) { + trigger(target, "clear", void 0, void 0, oldTarget); + } + return result; +} +function createForEach(isReadonly, isShallow) { + return function forEach(callback, thisArg) { + const observed = this; + const target = observed["__v_raw"]; + const rawTarget = toRaw(target); + const wrap = isShallow ? toShallow : isReadonly ? toReadonly : toReactive; + !isReadonly && track(rawTarget, "iterate", ITERATE_KEY); + return target.forEach((value, key) => { + return callback.call(thisArg, wrap(value), wrap(key), observed); + }); + }; +} +function createIterableMethod(method, isReadonly, isShallow) { + return function(...args) { + const target = this["__v_raw"]; + const rawTarget = toRaw(target); + const targetIsMap = isMap(rawTarget); + const isPair = method === "entries" || method === Symbol.iterator && targetIsMap; + const isKeyOnly = method === "keys" && targetIsMap; + const innerIterator = target[method](...args); + const wrap = isShallow ? toShallow : isReadonly ? toReadonly : toReactive; + !isReadonly && track( + rawTarget, + "iterate", + isKeyOnly ? MAP_KEY_ITERATE_KEY : ITERATE_KEY + ); + return { + // iterator protocol + next() { + const { value, done } = innerIterator.next(); + return done ? { value, done } : { + value: isPair ? [wrap(value[0]), wrap(value[1])] : wrap(value), + done + }; + }, + // iterable protocol + [Symbol.iterator]() { + return this; + } + }; + }; +} +function createReadonlyMethod(type) { + return function(...args) { + { + const key = args[0] ? `on key "${args[0]}" ` : ``; + console.warn( + `${capitalize(type)} operation ${key}failed: target is readonly.`, + toRaw(this) + ); + } + return type === "delete" ? false : type === "clear" ? void 0 : this; + }; +} +function createInstrumentations() { + const mutableInstrumentations2 = { + get(key) { + return get(this, key); + }, + get size() { + return size(this); + }, + has, + add, + set, + delete: deleteEntry, + clear, + forEach: createForEach(false, false) + }; + const shallowInstrumentations2 = { + get(key) { + return get(this, key, false, true); + }, + get size() { + return size(this); + }, + has, + add, + set, + delete: deleteEntry, + clear, + forEach: createForEach(false, true) + }; + const readonlyInstrumentations2 = { + get(key) { + return get(this, key, true); + }, + get size() { + return size(this, true); + }, + has(key) { + return has.call(this, key, true); + }, + add: createReadonlyMethod("add"), + set: createReadonlyMethod("set"), + delete: createReadonlyMethod("delete"), + clear: createReadonlyMethod("clear"), + forEach: createForEach(true, false) + }; + const shallowReadonlyInstrumentations2 = { + get(key) { + return get(this, key, true, true); + }, + get size() { + return size(this, true); + }, + has(key) { + return has.call(this, key, true); + }, + add: createReadonlyMethod("add"), + set: createReadonlyMethod("set"), + delete: createReadonlyMethod("delete"), + clear: createReadonlyMethod("clear"), + forEach: createForEach(true, true) + }; + const iteratorMethods = ["keys", "values", "entries", Symbol.iterator]; + iteratorMethods.forEach((method) => { + mutableInstrumentations2[method] = createIterableMethod( + method, + false, + false + ); + readonlyInstrumentations2[method] = createIterableMethod( + method, + true, + false + ); + shallowInstrumentations2[method] = createIterableMethod( + method, + false, + true + ); + shallowReadonlyInstrumentations2[method] = createIterableMethod( + method, + true, + true + ); + }); + return [ + mutableInstrumentations2, + readonlyInstrumentations2, + shallowInstrumentations2, + shallowReadonlyInstrumentations2 + ]; +} +const [ + mutableInstrumentations, + readonlyInstrumentations, + shallowInstrumentations, + shallowReadonlyInstrumentations +] = /* @__PURE__ */ createInstrumentations(); +function createInstrumentationGetter(isReadonly, shallow) { + const instrumentations = shallow ? isReadonly ? shallowReadonlyInstrumentations : shallowInstrumentations : isReadonly ? readonlyInstrumentations : mutableInstrumentations; + return (target, key, receiver) => { + if (key === "__v_isReactive") { + return !isReadonly; + } else if (key === "__v_isReadonly") { + return isReadonly; + } else if (key === "__v_raw") { + return target; + } + return Reflect.get( + hasOwn(instrumentations, key) && key in target ? instrumentations : target, + key, + receiver + ); + }; +} +const mutableCollectionHandlers = { + get: /* @__PURE__ */ createInstrumentationGetter(false, false) +}; +const shallowCollectionHandlers = { + get: /* @__PURE__ */ createInstrumentationGetter(false, true) +}; +const readonlyCollectionHandlers = { + get: /* @__PURE__ */ createInstrumentationGetter(true, false) +}; +const shallowReadonlyCollectionHandlers = { + get: /* @__PURE__ */ createInstrumentationGetter(true, true) +}; +function checkIdentityKeys(target, has2, key) { + const rawKey = toRaw(key); + if (rawKey !== key && has2.call(target, rawKey)) { + const type = toRawType(target); + console.warn( + `Reactive ${type} contains both the raw and reactive versions of the same object${type === `Map` ? ` as keys` : ``}, which can lead to inconsistencies. Avoid differentiating between the raw and reactive versions of an object and only use the reactive version if possible.` + ); + } +} + +const reactiveMap = /* @__PURE__ */ new WeakMap(); +const shallowReactiveMap = /* @__PURE__ */ new WeakMap(); +const readonlyMap = /* @__PURE__ */ new WeakMap(); +const shallowReadonlyMap = /* @__PURE__ */ new WeakMap(); +function targetTypeMap(rawType) { + switch (rawType) { + case "Object": + case "Array": + return 1 /* COMMON */; + case "Map": + case "Set": + case "WeakMap": + case "WeakSet": + return 2 /* COLLECTION */; + default: + return 0 /* INVALID */; + } +} +function getTargetType(value) { + return value["__v_skip"] || !Object.isExtensible(value) ? 0 /* INVALID */ : targetTypeMap(toRawType(value)); +} +function reactive(target) { + if (isReadonly(target)) { + return target; + } + return createReactiveObject( + target, + false, + mutableHandlers, + mutableCollectionHandlers, + reactiveMap + ); +} +function shallowReactive(target) { + return createReactiveObject( + target, + false, + shallowReactiveHandlers, + shallowCollectionHandlers, + shallowReactiveMap + ); +} +function readonly(target) { + return createReactiveObject( + target, + true, + readonlyHandlers, + readonlyCollectionHandlers, + readonlyMap + ); +} +function shallowReadonly(target) { + return createReactiveObject( + target, + true, + shallowReadonlyHandlers, + shallowReadonlyCollectionHandlers, + shallowReadonlyMap + ); +} +function createReactiveObject(target, isReadonly2, baseHandlers, collectionHandlers, proxyMap) { + if (!isObject(target)) { + { + console.warn(`value cannot be made reactive: ${String(target)}`); + } + return target; + } + if (target["__v_raw"] && !(isReadonly2 && target["__v_isReactive"])) { + return target; + } + const existingProxy = proxyMap.get(target); + if (existingProxy) { + return existingProxy; + } + const targetType = getTargetType(target); + if (targetType === 0 /* INVALID */) { + return target; + } + const proxy = new Proxy( + target, + targetType === 2 /* COLLECTION */ ? collectionHandlers : baseHandlers + ); + proxyMap.set(target, proxy); + return proxy; +} +function isReactive(value) { + if (isReadonly(value)) { + return isReactive(value["__v_raw"]); + } + return !!(value && value["__v_isReactive"]); +} +function isReadonly(value) { + return !!(value && value["__v_isReadonly"]); +} +function isShallow(value) { + return !!(value && value["__v_isShallow"]); +} +function isProxy(value) { + return isReactive(value) || isReadonly(value); +} +function toRaw(observed) { + const raw = observed && observed["__v_raw"]; + return raw ? toRaw(raw) : observed; +} +function markRaw(value) { + def(value, "__v_skip", true); + return value; +} +const toReactive = (value) => isObject(value) ? reactive(value) : value; +const toReadonly = (value) => isObject(value) ? readonly(value) : value; + +class ComputedRefImpl { + constructor(getter, _setter, isReadonly, isSSR) { + this._setter = _setter; + this.dep = void 0; + this.__v_isRef = true; + this["__v_isReadonly"] = false; + this.effect = new ReactiveEffect( + () => getter(this._value), + () => triggerRefValue(this, 1), + () => this.dep && scheduleEffects(this.dep) + ); + this.effect.computed = this; + this.effect.active = this._cacheable = !isSSR; + this["__v_isReadonly"] = isReadonly; + } + get value() { + const self = toRaw(this); + if (!self._cacheable || self.effect.dirty) { + if (hasChanged(self._value, self._value = self.effect.run())) { + triggerRefValue(self, 2); + } + } + trackRefValue(self); + if (self.effect._dirtyLevel >= 1) { + triggerRefValue(self, 1); + } + return self._value; + } + set value(newValue) { + this._setter(newValue); + } + // #region polyfill _dirty for backward compatibility third party code for Vue <= 3.3.x + get _dirty() { + return this.effect.dirty; + } + set _dirty(v) { + this.effect.dirty = v; + } + // #endregion +} +function computed$1(getterOrOptions, debugOptions, isSSR = false) { + let getter; + let setter; + const onlyGetter = isFunction(getterOrOptions); + if (onlyGetter) { + getter = getterOrOptions; + setter = () => { + console.warn("Write operation failed: computed value is readonly"); + } ; + } else { + getter = getterOrOptions.get; + setter = getterOrOptions.set; + } + const cRef = new ComputedRefImpl(getter, setter, onlyGetter || !setter, isSSR); + if (debugOptions && !isSSR) { + cRef.effect.onTrack = debugOptions.onTrack; + cRef.effect.onTrigger = debugOptions.onTrigger; + } + return cRef; +} + +function trackRefValue(ref2) { + if (shouldTrack && activeEffect) { + ref2 = toRaw(ref2); + trackEffect( + activeEffect, + ref2.dep || (ref2.dep = createDep( + () => ref2.dep = void 0, + ref2 instanceof ComputedRefImpl ? ref2 : void 0 + )), + { + target: ref2, + type: "get", + key: "value" + } + ); + } +} +function triggerRefValue(ref2, dirtyLevel = 2, newVal) { + ref2 = toRaw(ref2); + const dep = ref2.dep; + if (dep) { + triggerEffects( + dep, + dirtyLevel, + { + target: ref2, + type: "set", + key: "value", + newValue: newVal + } + ); + } +} +function isRef(r) { + return !!(r && r.__v_isRef === true); +} +function ref(value) { + return createRef(value, false); +} +function shallowRef(value) { + return createRef(value, true); +} +function createRef(rawValue, shallow) { + if (isRef(rawValue)) { + return rawValue; + } + return new RefImpl(rawValue, shallow); +} +class RefImpl { + constructor(value, __v_isShallow) { + this.__v_isShallow = __v_isShallow; + this.dep = void 0; + this.__v_isRef = true; + this._rawValue = __v_isShallow ? value : toRaw(value); + this._value = __v_isShallow ? value : toReactive(value); + } + get value() { + trackRefValue(this); + return this._value; + } + set value(newVal) { + const useDirectValue = this.__v_isShallow || isShallow(newVal) || isReadonly(newVal); + newVal = useDirectValue ? newVal : toRaw(newVal); + if (hasChanged(newVal, this._rawValue)) { + this._rawValue = newVal; + this._value = useDirectValue ? newVal : toReactive(newVal); + triggerRefValue(this, 2, newVal); + } + } +} +function triggerRef(ref2) { + triggerRefValue(ref2, 2, ref2.value ); +} +function unref(ref2) { + return isRef(ref2) ? ref2.value : ref2; +} +function toValue(source) { + return isFunction(source) ? source() : unref(source); +} +const shallowUnwrapHandlers = { + get: (target, key, receiver) => unref(Reflect.get(target, key, receiver)), + set: (target, key, value, receiver) => { + const oldValue = target[key]; + if (isRef(oldValue) && !isRef(value)) { + oldValue.value = value; + return true; + } else { + return Reflect.set(target, key, value, receiver); + } + } +}; +function proxyRefs(objectWithRefs) { + return isReactive(objectWithRefs) ? objectWithRefs : new Proxy(objectWithRefs, shallowUnwrapHandlers); +} +class CustomRefImpl { + constructor(factory) { + this.dep = void 0; + this.__v_isRef = true; + const { get, set } = factory( + () => trackRefValue(this), + () => triggerRefValue(this) + ); + this._get = get; + this._set = set; + } + get value() { + return this._get(); + } + set value(newVal) { + this._set(newVal); + } +} +function customRef(factory) { + return new CustomRefImpl(factory); +} +function toRefs(object) { + if (!isProxy(object)) { + console.warn(`toRefs() expects a reactive object but received a plain one.`); + } + const ret = isArray(object) ? new Array(object.length) : {}; + for (const key in object) { + ret[key] = propertyToRef(object, key); + } + return ret; +} +class ObjectRefImpl { + constructor(_object, _key, _defaultValue) { + this._object = _object; + this._key = _key; + this._defaultValue = _defaultValue; + this.__v_isRef = true; + } + get value() { + const val = this._object[this._key]; + return val === void 0 ? this._defaultValue : val; + } + set value(newVal) { + this._object[this._key] = newVal; + } + get dep() { + return getDepFromReactive(toRaw(this._object), this._key); + } +} +class GetterRefImpl { + constructor(_getter) { + this._getter = _getter; + this.__v_isRef = true; + this.__v_isReadonly = true; + } + get value() { + return this._getter(); + } +} +function toRef(source, key, defaultValue) { + if (isRef(source)) { + return source; + } else if (isFunction(source)) { + return new GetterRefImpl(source); + } else if (isObject(source) && arguments.length > 1) { + return propertyToRef(source, key, defaultValue); + } else { + return ref(source); + } +} +function propertyToRef(source, key, defaultValue) { + const val = source[key]; + return isRef(val) ? val : new ObjectRefImpl(source, key, defaultValue); +} + +const TrackOpTypes = { + "GET": "get", + "HAS": "has", + "ITERATE": "iterate" +}; +const TriggerOpTypes = { + "SET": "set", + "ADD": "add", + "DELETE": "delete", + "CLEAR": "clear" +}; + +const stack$1 = []; +function pushWarningContext(vnode) { + stack$1.push(vnode); +} +function popWarningContext() { + stack$1.pop(); +} +function warn$1(msg, ...args) { + pauseTracking(); + const instance = stack$1.length ? stack$1[stack$1.length - 1].component : null; + const appWarnHandler = instance && instance.appContext.config.warnHandler; + const trace = getComponentTrace(); + if (appWarnHandler) { + callWithErrorHandling( + appWarnHandler, + instance, + 11, + [ + msg + args.join(""), + instance && instance.proxy, + trace.map( + ({ vnode }) => `at <${formatComponentName(instance, vnode.type)}>` + ).join("\n"), + trace + ] + ); + } else { + const warnArgs = [`[Vue warn]: ${msg}`, ...args]; + if (trace.length && // avoid spamming console during tests + true) { + warnArgs.push(` +`, ...formatTrace(trace)); + } + console.warn(...warnArgs); + } + resetTracking(); +} +function getComponentTrace() { + let currentVNode = stack$1[stack$1.length - 1]; + if (!currentVNode) { + return []; + } + const normalizedStack = []; + while (currentVNode) { + const last = normalizedStack[0]; + if (last && last.vnode === currentVNode) { + last.recurseCount++; + } else { + normalizedStack.push({ + vnode: currentVNode, + recurseCount: 0 + }); + } + const parentInstance = currentVNode.component && currentVNode.component.parent; + currentVNode = parentInstance && parentInstance.vnode; + } + return normalizedStack; +} +function formatTrace(trace) { + const logs = []; + trace.forEach((entry, i) => { + logs.push(...i === 0 ? [] : [` +`], ...formatTraceEntry(entry)); + }); + return logs; +} +function formatTraceEntry({ vnode, recurseCount }) { + const postfix = recurseCount > 0 ? `... (${recurseCount} recursive calls)` : ``; + const isRoot = vnode.component ? vnode.component.parent == null : false; + const open = ` at <${formatComponentName( + vnode.component, + vnode.type, + isRoot + )}`; + const close = `>` + postfix; + return vnode.props ? [open, ...formatProps(vnode.props), close] : [open + close]; +} +function formatProps(props) { + const res = []; + const keys = Object.keys(props); + keys.slice(0, 3).forEach((key) => { + res.push(...formatProp(key, props[key])); + }); + if (keys.length > 3) { + res.push(` ...`); + } + return res; +} +function formatProp(key, value, raw) { + if (isString(value)) { + value = JSON.stringify(value); + return raw ? value : [`${key}=${value}`]; + } else if (typeof value === "number" || typeof value === "boolean" || value == null) { + return raw ? value : [`${key}=${value}`]; + } else if (isRef(value)) { + value = formatProp(key, toRaw(value.value), true); + return raw ? value : [`${key}=Ref<`, value, `>`]; + } else if (isFunction(value)) { + return [`${key}=fn${value.name ? `<${value.name}>` : ``}`]; + } else { + value = toRaw(value); + return raw ? value : [`${key}=`, value]; + } +} +function assertNumber(val, type) { + if (val === void 0) { + return; + } else if (typeof val !== "number") { + warn$1(`${type} is not a valid number - got ${JSON.stringify(val)}.`); + } else if (isNaN(val)) { + warn$1(`${type} is NaN - the duration expression might be incorrect.`); + } +} + +const ErrorCodes = { + "SETUP_FUNCTION": 0, + "0": "SETUP_FUNCTION", + "RENDER_FUNCTION": 1, + "1": "RENDER_FUNCTION", + "WATCH_GETTER": 2, + "2": "WATCH_GETTER", + "WATCH_CALLBACK": 3, + "3": "WATCH_CALLBACK", + "WATCH_CLEANUP": 4, + "4": "WATCH_CLEANUP", + "NATIVE_EVENT_HANDLER": 5, + "5": "NATIVE_EVENT_HANDLER", + "COMPONENT_EVENT_HANDLER": 6, + "6": "COMPONENT_EVENT_HANDLER", + "VNODE_HOOK": 7, + "7": "VNODE_HOOK", + "DIRECTIVE_HOOK": 8, + "8": "DIRECTIVE_HOOK", + "TRANSITION_HOOK": 9, + "9": "TRANSITION_HOOK", + "APP_ERROR_HANDLER": 10, + "10": "APP_ERROR_HANDLER", + "APP_WARN_HANDLER": 11, + "11": "APP_WARN_HANDLER", + "FUNCTION_REF": 12, + "12": "FUNCTION_REF", + "ASYNC_COMPONENT_LOADER": 13, + "13": "ASYNC_COMPONENT_LOADER", + "SCHEDULER": 14, + "14": "SCHEDULER" +}; +const ErrorTypeStrings$1 = { + ["sp"]: "serverPrefetch hook", + ["bc"]: "beforeCreate hook", + ["c"]: "created hook", + ["bm"]: "beforeMount hook", + ["m"]: "mounted hook", + ["bu"]: "beforeUpdate hook", + ["u"]: "updated", + ["bum"]: "beforeUnmount hook", + ["um"]: "unmounted hook", + ["a"]: "activated hook", + ["da"]: "deactivated hook", + ["ec"]: "errorCaptured hook", + ["rtc"]: "renderTracked hook", + ["rtg"]: "renderTriggered hook", + [0]: "setup function", + [1]: "render function", + [2]: "watcher getter", + [3]: "watcher callback", + [4]: "watcher cleanup function", + [5]: "native event handler", + [6]: "component event handler", + [7]: "vnode hook", + [8]: "directive hook", + [9]: "transition hook", + [10]: "app errorHandler", + [11]: "app warnHandler", + [12]: "ref function", + [13]: "async component loader", + [14]: "scheduler flush. This is likely a Vue internals bug. Please open an issue at https://github.com/vuejs/core ." +}; +function callWithErrorHandling(fn, instance, type, args) { + let res; + try { + res = args ? fn(...args) : fn(); + } catch (err) { + handleError(err, instance, type); + } + return res; +} +function callWithAsyncErrorHandling(fn, instance, type, args) { + if (isFunction(fn)) { + const res = callWithErrorHandling(fn, instance, type, args); + if (res && isPromise(res)) { + res.catch((err) => { + handleError(err, instance, type); + }); + } + return res; + } + const values = []; + for (let i = 0; i < fn.length; i++) { + values.push(callWithAsyncErrorHandling(fn[i], instance, type, args)); + } + return values; +} +function handleError(err, instance, type, throwInDev = true) { + const contextVNode = instance ? instance.vnode : null; + if (instance) { + let cur = instance.parent; + const exposedInstance = instance.proxy; + const errorInfo = ErrorTypeStrings$1[type] ; + while (cur) { + const errorCapturedHooks = cur.ec; + if (errorCapturedHooks) { + for (let i = 0; i < errorCapturedHooks.length; i++) { + if (errorCapturedHooks[i](err, exposedInstance, errorInfo) === false) { + return; + } + } + } + cur = cur.parent; + } + const appErrorHandler = instance.appContext.config.errorHandler; + if (appErrorHandler) { + callWithErrorHandling( + appErrorHandler, + null, + 10, + [err, exposedInstance, errorInfo] + ); + return; + } + } + logError(err, type, contextVNode, throwInDev); +} +function logError(err, type, contextVNode, throwInDev = true) { + { + const info = ErrorTypeStrings$1[type]; + if (contextVNode) { + pushWarningContext(contextVNode); + } + warn$1(`Unhandled error${info ? ` during execution of ${info}` : ``}`); + if (contextVNode) { + popWarningContext(); + } + if (throwInDev) { + throw err; + } else { + console.error(err); + } + } +} + +let isFlushing = false; +let isFlushPending = false; +const queue = []; +let flushIndex = 0; +const pendingPostFlushCbs = []; +let activePostFlushCbs = null; +let postFlushIndex = 0; +const resolvedPromise = /* @__PURE__ */ Promise.resolve(); +let currentFlushPromise = null; +const RECURSION_LIMIT = 100; +function nextTick(fn) { + const p = currentFlushPromise || resolvedPromise; + return fn ? p.then(this ? fn.bind(this) : fn) : p; +} +function findInsertionIndex(id) { + let start = flushIndex + 1; + let end = queue.length; + while (start < end) { + const middle = start + end >>> 1; + const middleJob = queue[middle]; + const middleJobId = getId(middleJob); + if (middleJobId < id || middleJobId === id && middleJob.pre) { + start = middle + 1; + } else { + end = middle; + } + } + return start; +} +function queueJob(job) { + if (!queue.length || !queue.includes( + job, + isFlushing && job.allowRecurse ? flushIndex + 1 : flushIndex + )) { + if (job.id == null) { + queue.push(job); + } else { + queue.splice(findInsertionIndex(job.id), 0, job); + } + queueFlush(); + } +} +function queueFlush() { + if (!isFlushing && !isFlushPending) { + isFlushPending = true; + currentFlushPromise = resolvedPromise.then(flushJobs); + } +} +function invalidateJob(job) { + const i = queue.indexOf(job); + if (i > flushIndex) { + queue.splice(i, 1); + } +} +function queuePostFlushCb(cb) { + if (!isArray(cb)) { + if (!activePostFlushCbs || !activePostFlushCbs.includes( + cb, + cb.allowRecurse ? postFlushIndex + 1 : postFlushIndex + )) { + pendingPostFlushCbs.push(cb); + } + } else { + pendingPostFlushCbs.push(...cb); + } + queueFlush(); +} +function flushPreFlushCbs(instance, seen, i = isFlushing ? flushIndex + 1 : 0) { + { + seen = seen || /* @__PURE__ */ new Map(); + } + for (; i < queue.length; i++) { + const cb = queue[i]; + if (cb && cb.pre) { + if (instance && cb.id !== instance.uid) { + continue; + } + if (checkRecursiveUpdates(seen, cb)) { + continue; + } + queue.splice(i, 1); + i--; + cb(); + } + } +} +function flushPostFlushCbs(seen) { + if (pendingPostFlushCbs.length) { + const deduped = [...new Set(pendingPostFlushCbs)].sort( + (a, b) => getId(a) - getId(b) + ); + pendingPostFlushCbs.length = 0; + if (activePostFlushCbs) { + activePostFlushCbs.push(...deduped); + return; + } + activePostFlushCbs = deduped; + { + seen = seen || /* @__PURE__ */ new Map(); + } + for (postFlushIndex = 0; postFlushIndex < activePostFlushCbs.length; postFlushIndex++) { + if (checkRecursiveUpdates(seen, activePostFlushCbs[postFlushIndex])) { + continue; + } + activePostFlushCbs[postFlushIndex](); + } + activePostFlushCbs = null; + postFlushIndex = 0; + } +} +const getId = (job) => job.id == null ? Infinity : job.id; +const comparator = (a, b) => { + const diff = getId(a) - getId(b); + if (diff === 0) { + if (a.pre && !b.pre) + return -1; + if (b.pre && !a.pre) + return 1; + } + return diff; +}; +function flushJobs(seen) { + isFlushPending = false; + isFlushing = true; + { + seen = seen || /* @__PURE__ */ new Map(); + } + queue.sort(comparator); + const check = (job) => checkRecursiveUpdates(seen, job) ; + try { + for (flushIndex = 0; flushIndex < queue.length; flushIndex++) { + const job = queue[flushIndex]; + if (job && job.active !== false) { + if (check(job)) { + continue; + } + callWithErrorHandling(job, null, 14); + } + } + } finally { + flushIndex = 0; + queue.length = 0; + flushPostFlushCbs(seen); + isFlushing = false; + currentFlushPromise = null; + if (queue.length || pendingPostFlushCbs.length) { + flushJobs(seen); + } + } +} +function checkRecursiveUpdates(seen, fn) { + if (!seen.has(fn)) { + seen.set(fn, 1); + } else { + const count = seen.get(fn); + if (count > RECURSION_LIMIT) { + const instance = fn.ownerInstance; + const componentName = instance && getComponentName(instance.type); + handleError( + `Maximum recursive updates exceeded${componentName ? ` in component <${componentName}>` : ``}. This means you have a reactive effect that is mutating its own dependencies and thus recursively triggering itself. Possible sources include component template, render function, updated hook or watcher source function.`, + null, + 10 + ); + return true; + } else { + seen.set(fn, count + 1); + } + } +} + +let isHmrUpdating = false; +const hmrDirtyComponents = /* @__PURE__ */ new Set(); +{ + getGlobalThis().__VUE_HMR_RUNTIME__ = { + createRecord: tryWrap(createRecord), + rerender: tryWrap(rerender), + reload: tryWrap(reload) + }; +} +const map = /* @__PURE__ */ new Map(); +function registerHMR(instance) { + const id = instance.type.__hmrId; + let record = map.get(id); + if (!record) { + createRecord(id, instance.type); + record = map.get(id); + } + record.instances.add(instance); +} +function unregisterHMR(instance) { + map.get(instance.type.__hmrId).instances.delete(instance); +} +function createRecord(id, initialDef) { + if (map.has(id)) { + return false; + } + map.set(id, { + initialDef: normalizeClassComponent(initialDef), + instances: /* @__PURE__ */ new Set() + }); + return true; +} +function normalizeClassComponent(component) { + return isClassComponent(component) ? component.__vccOpts : component; +} +function rerender(id, newRender) { + const record = map.get(id); + if (!record) { + return; + } + record.initialDef.render = newRender; + [...record.instances].forEach((instance) => { + if (newRender) { + instance.render = newRender; + normalizeClassComponent(instance.type).render = newRender; + } + instance.renderCache = []; + isHmrUpdating = true; + instance.effect.dirty = true; + instance.update(); + isHmrUpdating = false; + }); +} +function reload(id, newComp) { + const record = map.get(id); + if (!record) + return; + newComp = normalizeClassComponent(newComp); + updateComponentDef(record.initialDef, newComp); + const instances = [...record.instances]; + for (const instance of instances) { + const oldComp = normalizeClassComponent(instance.type); + if (!hmrDirtyComponents.has(oldComp)) { + if (oldComp !== record.initialDef) { + updateComponentDef(oldComp, newComp); + } + hmrDirtyComponents.add(oldComp); + } + instance.appContext.propsCache.delete(instance.type); + instance.appContext.emitsCache.delete(instance.type); + instance.appContext.optionsCache.delete(instance.type); + if (instance.ceReload) { + hmrDirtyComponents.add(oldComp); + instance.ceReload(newComp.styles); + hmrDirtyComponents.delete(oldComp); + } else if (instance.parent) { + instance.parent.effect.dirty = true; + queueJob(instance.parent.update); + } else if (instance.appContext.reload) { + instance.appContext.reload(); + } else if (typeof window !== "undefined") { + window.location.reload(); + } else { + console.warn( + "[HMR] Root or manually mounted instance modified. Full reload required." + ); + } + } + queuePostFlushCb(() => { + for (const instance of instances) { + hmrDirtyComponents.delete( + normalizeClassComponent(instance.type) + ); + } + }); +} +function updateComponentDef(oldComp, newComp) { + extend(oldComp, newComp); + for (const key in oldComp) { + if (key !== "__file" && !(key in newComp)) { + delete oldComp[key]; + } + } +} +function tryWrap(fn) { + return (id, arg) => { + try { + return fn(id, arg); + } catch (e) { + console.error(e); + console.warn( + `[HMR] Something went wrong during Vue component hot-reload. Full reload required.` + ); + } + }; +} + +let devtools$1; +let buffer = []; +let devtoolsNotInstalled = false; +function emit$1(event, ...args) { + if (devtools$1) { + devtools$1.emit(event, ...args); + } else if (!devtoolsNotInstalled) { + buffer.push({ event, args }); + } +} +function setDevtoolsHook$1(hook, target) { + var _a, _b; + devtools$1 = hook; + if (devtools$1) { + devtools$1.enabled = true; + buffer.forEach(({ event, args }) => devtools$1.emit(event, ...args)); + buffer = []; + } else if ( + // handle late devtools injection - only do this if we are in an actual + // browser environment to avoid the timer handle stalling test runner exit + // (#4815) + typeof window !== "undefined" && // some envs mock window but not fully + window.HTMLElement && // also exclude jsdom + !((_b = (_a = window.navigator) == null ? void 0 : _a.userAgent) == null ? void 0 : _b.includes("jsdom")) + ) { + const replay = target.__VUE_DEVTOOLS_HOOK_REPLAY__ = target.__VUE_DEVTOOLS_HOOK_REPLAY__ || []; + replay.push((newHook) => { + setDevtoolsHook$1(newHook, target); + }); + setTimeout(() => { + if (!devtools$1) { + target.__VUE_DEVTOOLS_HOOK_REPLAY__ = null; + devtoolsNotInstalled = true; + buffer = []; + } + }, 3e3); + } else { + devtoolsNotInstalled = true; + buffer = []; + } +} +function devtoolsInitApp(app, version) { + emit$1("app:init" /* APP_INIT */, app, version, { + Fragment, + Text, + Comment, + Static + }); +} +function devtoolsUnmountApp(app) { + emit$1("app:unmount" /* APP_UNMOUNT */, app); +} +const devtoolsComponentAdded = /* @__PURE__ */ createDevtoolsComponentHook( + "component:added" /* COMPONENT_ADDED */ +); +const devtoolsComponentUpdated = /* @__PURE__ */ createDevtoolsComponentHook("component:updated" /* COMPONENT_UPDATED */); +const _devtoolsComponentRemoved = /* @__PURE__ */ createDevtoolsComponentHook( + "component:removed" /* COMPONENT_REMOVED */ +); +const devtoolsComponentRemoved = (component) => { + if (devtools$1 && typeof devtools$1.cleanupBuffer === "function" && // remove the component if it wasn't buffered + !devtools$1.cleanupBuffer(component)) { + _devtoolsComponentRemoved(component); + } +}; +function createDevtoolsComponentHook(hook) { + return (component) => { + emit$1( + hook, + component.appContext.app, + component.uid, + component.parent ? component.parent.uid : void 0, + component + ); + }; +} +const devtoolsPerfStart = /* @__PURE__ */ createDevtoolsPerformanceHook( + "perf:start" /* PERFORMANCE_START */ +); +const devtoolsPerfEnd = /* @__PURE__ */ createDevtoolsPerformanceHook( + "perf:end" /* PERFORMANCE_END */ +); +function createDevtoolsPerformanceHook(hook) { + return (component, type, time) => { + emit$1(hook, component.appContext.app, component.uid, component, type, time); + }; +} +function devtoolsComponentEmit(component, event, params) { + emit$1( + "component:emit" /* COMPONENT_EMIT */, + component.appContext.app, + component, + event, + params + ); +} + +function emit(instance, event, ...rawArgs) { + if (instance.isUnmounted) + return; + const props = instance.vnode.props || EMPTY_OBJ; + { + const { + emitsOptions, + propsOptions: [propsOptions] + } = instance; + if (emitsOptions) { + if (!(event in emitsOptions) && true) { + if (!propsOptions || !(toHandlerKey(event) in propsOptions)) { + warn$1( + `Component emitted event "${event}" but it is neither declared in the emits option nor as an "${toHandlerKey(event)}" prop.` + ); + } + } else { + const validator = emitsOptions[event]; + if (isFunction(validator)) { + const isValid = validator(...rawArgs); + if (!isValid) { + warn$1( + `Invalid event arguments: event validation failed for event "${event}".` + ); + } + } + } + } + } + let args = rawArgs; + const isModelListener = event.startsWith("update:"); + const modelArg = isModelListener && event.slice(7); + if (modelArg && modelArg in props) { + const modifiersKey = `${modelArg === "modelValue" ? "model" : modelArg}Modifiers`; + const { number, trim } = props[modifiersKey] || EMPTY_OBJ; + if (trim) { + args = rawArgs.map((a) => isString(a) ? a.trim() : a); + } + if (number) { + args = rawArgs.map(looseToNumber); + } + } + { + devtoolsComponentEmit(instance, event, args); + } + { + const lowerCaseEvent = event.toLowerCase(); + if (lowerCaseEvent !== event && props[toHandlerKey(lowerCaseEvent)]) { + warn$1( + `Event "${lowerCaseEvent}" is emitted in component ${formatComponentName( + instance, + instance.type + )} but the handler is registered for "${event}". Note that HTML attributes are case-insensitive and you cannot use v-on to listen to camelCase events when using in-DOM templates. You should probably use "${hyphenate( + event + )}" instead of "${event}".` + ); + } + } + let handlerName; + let handler = props[handlerName = toHandlerKey(event)] || // also try camelCase event handler (#2249) + props[handlerName = toHandlerKey(camelize(event))]; + if (!handler && isModelListener) { + handler = props[handlerName = toHandlerKey(hyphenate(event))]; + } + if (handler) { + callWithAsyncErrorHandling( + handler, + instance, + 6, + args + ); + } + const onceHandler = props[handlerName + `Once`]; + if (onceHandler) { + if (!instance.emitted) { + instance.emitted = {}; + } else if (instance.emitted[handlerName]) { + return; + } + instance.emitted[handlerName] = true; + callWithAsyncErrorHandling( + onceHandler, + instance, + 6, + args + ); + } +} +function normalizeEmitsOptions(comp, appContext, asMixin = false) { + const cache = appContext.emitsCache; + const cached = cache.get(comp); + if (cached !== void 0) { + return cached; + } + const raw = comp.emits; + let normalized = {}; + let hasExtends = false; + if (!isFunction(comp)) { + const extendEmits = (raw2) => { + const normalizedFromExtend = normalizeEmitsOptions(raw2, appContext, true); + if (normalizedFromExtend) { + hasExtends = true; + extend(normalized, normalizedFromExtend); + } + }; + if (!asMixin && appContext.mixins.length) { + appContext.mixins.forEach(extendEmits); + } + if (comp.extends) { + extendEmits(comp.extends); + } + if (comp.mixins) { + comp.mixins.forEach(extendEmits); + } + } + if (!raw && !hasExtends) { + if (isObject(comp)) { + cache.set(comp, null); + } + return null; + } + if (isArray(raw)) { + raw.forEach((key) => normalized[key] = null); + } else { + extend(normalized, raw); + } + if (isObject(comp)) { + cache.set(comp, normalized); + } + return normalized; +} +function isEmitListener(options, key) { + if (!options || !isOn(key)) { + return false; + } + key = key.slice(2).replace(/Once$/, ""); + return hasOwn(options, key[0].toLowerCase() + key.slice(1)) || hasOwn(options, hyphenate(key)) || hasOwn(options, key); +} + +let currentRenderingInstance = null; +let currentScopeId = null; +function setCurrentRenderingInstance(instance) { + const prev = currentRenderingInstance; + currentRenderingInstance = instance; + currentScopeId = instance && instance.type.__scopeId || null; + return prev; +} +function pushScopeId(id) { + currentScopeId = id; +} +function popScopeId() { + currentScopeId = null; +} +const withScopeId = (_id) => withCtx; +function withCtx(fn, ctx = currentRenderingInstance, isNonScopedSlot) { + if (!ctx) + return fn; + if (fn._n) { + return fn; + } + const renderFnWithContext = (...args) => { + if (renderFnWithContext._d) { + setBlockTracking(-1); + } + const prevInstance = setCurrentRenderingInstance(ctx); + let res; + try { + res = fn(...args); + } finally { + setCurrentRenderingInstance(prevInstance); + if (renderFnWithContext._d) { + setBlockTracking(1); + } + } + { + devtoolsComponentUpdated(ctx); + } + return res; + }; + renderFnWithContext._n = true; + renderFnWithContext._c = true; + renderFnWithContext._d = true; + return renderFnWithContext; +} + +let accessedAttrs = false; +function markAttrsAccessed() { + accessedAttrs = true; +} +function renderComponentRoot(instance) { + const { + type: Component, + vnode, + proxy, + withProxy, + props, + propsOptions: [propsOptions], + slots, + attrs, + emit, + render, + renderCache, + data, + setupState, + ctx, + inheritAttrs + } = instance; + let result; + let fallthroughAttrs; + const prev = setCurrentRenderingInstance(instance); + { + accessedAttrs = false; + } + try { + if (vnode.shapeFlag & 4) { + const proxyToUse = withProxy || proxy; + const thisProxy = setupState.__isScriptSetup ? new Proxy(proxyToUse, { + get(target, key, receiver) { + warn$1( + `Property '${String( + key + )}' was accessed via 'this'. Avoid using 'this' in templates.` + ); + return Reflect.get(target, key, receiver); + } + }) : proxyToUse; + result = normalizeVNode( + render.call( + thisProxy, + proxyToUse, + renderCache, + props, + setupState, + data, + ctx + ) + ); + fallthroughAttrs = attrs; + } else { + const render2 = Component; + if (attrs === props) { + markAttrsAccessed(); + } + result = normalizeVNode( + render2.length > 1 ? render2( + props, + true ? { + get attrs() { + markAttrsAccessed(); + return attrs; + }, + slots, + emit + } : { attrs, slots, emit } + ) : render2( + props, + null + /* we know it doesn't need it */ + ) + ); + fallthroughAttrs = Component.props ? attrs : getFunctionalFallthrough(attrs); + } + } catch (err) { + blockStack.length = 0; + handleError(err, instance, 1); + result = createVNode(Comment); + } + let root = result; + let setRoot = void 0; + if (result.patchFlag > 0 && result.patchFlag & 2048) { + [root, setRoot] = getChildRoot(result); + } + if (fallthroughAttrs && inheritAttrs !== false) { + const keys = Object.keys(fallthroughAttrs); + const { shapeFlag } = root; + if (keys.length) { + if (shapeFlag & (1 | 6)) { + if (propsOptions && keys.some(isModelListener)) { + fallthroughAttrs = filterModelListeners( + fallthroughAttrs, + propsOptions + ); + } + root = cloneVNode(root, fallthroughAttrs); + } else if (!accessedAttrs && root.type !== Comment) { + const allAttrs = Object.keys(attrs); + const eventAttrs = []; + const extraAttrs = []; + for (let i = 0, l = allAttrs.length; i < l; i++) { + const key = allAttrs[i]; + if (isOn(key)) { + if (!isModelListener(key)) { + eventAttrs.push(key[2].toLowerCase() + key.slice(3)); + } + } else { + extraAttrs.push(key); + } + } + if (extraAttrs.length) { + warn$1( + `Extraneous non-props attributes (${extraAttrs.join(", ")}) were passed to component but could not be automatically inherited because component renders fragment or text root nodes.` + ); + } + if (eventAttrs.length) { + warn$1( + `Extraneous non-emits event listeners (${eventAttrs.join(", ")}) were passed to component but could not be automatically inherited because component renders fragment or text root nodes. If the listener is intended to be a component custom event listener only, declare it using the "emits" option.` + ); + } + } + } + } + if (vnode.dirs) { + if (!isElementRoot(root)) { + warn$1( + `Runtime directive used on component with non-element root node. The directives will not function as intended.` + ); + } + root = cloneVNode(root); + root.dirs = root.dirs ? root.dirs.concat(vnode.dirs) : vnode.dirs; + } + if (vnode.transition) { + if (!isElementRoot(root)) { + warn$1( + `Component inside renders non-element root node that cannot be animated.` + ); + } + root.transition = vnode.transition; + } + if (setRoot) { + setRoot(root); + } else { + result = root; + } + setCurrentRenderingInstance(prev); + return result; +} +const getChildRoot = (vnode) => { + const rawChildren = vnode.children; + const dynamicChildren = vnode.dynamicChildren; + const childRoot = filterSingleRoot(rawChildren, false); + if (!childRoot) { + return [vnode, void 0]; + } else if (childRoot.patchFlag > 0 && childRoot.patchFlag & 2048) { + return getChildRoot(childRoot); + } + const index = rawChildren.indexOf(childRoot); + const dynamicIndex = dynamicChildren ? dynamicChildren.indexOf(childRoot) : -1; + const setRoot = (updatedRoot) => { + rawChildren[index] = updatedRoot; + if (dynamicChildren) { + if (dynamicIndex > -1) { + dynamicChildren[dynamicIndex] = updatedRoot; + } else if (updatedRoot.patchFlag > 0) { + vnode.dynamicChildren = [...dynamicChildren, updatedRoot]; + } + } + }; + return [normalizeVNode(childRoot), setRoot]; +}; +function filterSingleRoot(children, recurse = true) { + let singleRoot; + for (let i = 0; i < children.length; i++) { + const child = children[i]; + if (isVNode(child)) { + if (child.type !== Comment || child.children === "v-if") { + if (singleRoot) { + return; + } else { + singleRoot = child; + if (recurse && singleRoot.patchFlag > 0 && singleRoot.patchFlag & 2048) { + return filterSingleRoot(singleRoot.children); + } + } + } + } else { + return; + } + } + return singleRoot; +} +const getFunctionalFallthrough = (attrs) => { + let res; + for (const key in attrs) { + if (key === "class" || key === "style" || isOn(key)) { + (res || (res = {}))[key] = attrs[key]; + } + } + return res; +}; +const filterModelListeners = (attrs, props) => { + const res = {}; + for (const key in attrs) { + if (!isModelListener(key) || !(key.slice(9) in props)) { + res[key] = attrs[key]; + } + } + return res; +}; +const isElementRoot = (vnode) => { + return vnode.shapeFlag & (6 | 1) || vnode.type === Comment; +}; +function shouldUpdateComponent(prevVNode, nextVNode, optimized) { + const { props: prevProps, children: prevChildren, component } = prevVNode; + const { props: nextProps, children: nextChildren, patchFlag } = nextVNode; + const emits = component.emitsOptions; + if ((prevChildren || nextChildren) && isHmrUpdating) { + return true; + } + if (nextVNode.dirs || nextVNode.transition) { + return true; + } + if (optimized && patchFlag >= 0) { + if (patchFlag & 1024) { + return true; + } + if (patchFlag & 16) { + if (!prevProps) { + return !!nextProps; + } + return hasPropsChanged(prevProps, nextProps, emits); + } else if (patchFlag & 8) { + const dynamicProps = nextVNode.dynamicProps; + for (let i = 0; i < dynamicProps.length; i++) { + const key = dynamicProps[i]; + if (nextProps[key] !== prevProps[key] && !isEmitListener(emits, key)) { + return true; + } + } + } + } else { + if (prevChildren || nextChildren) { + if (!nextChildren || !nextChildren.$stable) { + return true; + } + } + if (prevProps === nextProps) { + return false; + } + if (!prevProps) { + return !!nextProps; + } + if (!nextProps) { + return true; + } + return hasPropsChanged(prevProps, nextProps, emits); + } + return false; +} +function hasPropsChanged(prevProps, nextProps, emitsOptions) { + const nextKeys = Object.keys(nextProps); + if (nextKeys.length !== Object.keys(prevProps).length) { + return true; + } + for (let i = 0; i < nextKeys.length; i++) { + const key = nextKeys[i]; + if (nextProps[key] !== prevProps[key] && !isEmitListener(emitsOptions, key)) { + return true; + } + } + return false; +} +function updateHOCHostEl({ vnode, parent }, el) { + while (parent) { + const root = parent.subTree; + if (root.suspense && root.suspense.activeBranch === vnode) { + root.el = vnode.el; + } + if (root === vnode) { + (vnode = parent.vnode).el = el; + parent = parent.parent; + } else { + break; + } + } +} + +const COMPONENTS = "components"; +const DIRECTIVES = "directives"; +function resolveComponent(name, maybeSelfReference) { + return resolveAsset(COMPONENTS, name, true, maybeSelfReference) || name; +} +const NULL_DYNAMIC_COMPONENT = Symbol.for("v-ndc"); +function resolveDynamicComponent(component) { + if (isString(component)) { + return resolveAsset(COMPONENTS, component, false) || component; + } else { + return component || NULL_DYNAMIC_COMPONENT; + } +} +function resolveDirective(name) { + return resolveAsset(DIRECTIVES, name); +} +function resolveAsset(type, name, warnMissing = true, maybeSelfReference = false) { + const instance = currentRenderingInstance || currentInstance; + if (instance) { + const Component = instance.type; + if (type === COMPONENTS) { + const selfName = getComponentName( + Component, + false + ); + if (selfName && (selfName === name || selfName === camelize(name) || selfName === capitalize(camelize(name)))) { + return Component; + } + } + const res = ( + // local registration + // check instance[type] first which is resolved for options API + resolve(instance[type] || Component[type], name) || // global registration + resolve(instance.appContext[type], name) + ); + if (!res && maybeSelfReference) { + return Component; + } + if (warnMissing && !res) { + const extra = type === COMPONENTS ? ` +If this is a native custom element, make sure to exclude it from component resolution via compilerOptions.isCustomElement.` : ``; + warn$1(`Failed to resolve ${type.slice(0, -1)}: ${name}${extra}`); + } + return res; + } else { + warn$1( + `resolve${capitalize(type.slice(0, -1))} can only be used in render() or setup().` + ); + } +} +function resolve(registry, name) { + return registry && (registry[name] || registry[camelize(name)] || registry[capitalize(camelize(name))]); +} + +const isSuspense = (type) => type.__isSuspense; +let suspenseId = 0; +const SuspenseImpl = { + name: "Suspense", + // In order to make Suspense tree-shakable, we need to avoid importing it + // directly in the renderer. The renderer checks for the __isSuspense flag + // on a vnode's type and calls the `process` method, passing in renderer + // internals. + __isSuspense: true, + process(n1, n2, container, anchor, parentComponent, parentSuspense, namespace, slotScopeIds, optimized, rendererInternals) { + if (n1 == null) { + mountSuspense( + n2, + container, + anchor, + parentComponent, + parentSuspense, + namespace, + slotScopeIds, + optimized, + rendererInternals + ); + } else { + if (parentSuspense && parentSuspense.deps > 0) { + n2.suspense = n1.suspense; + return; + } + patchSuspense( + n1, + n2, + container, + anchor, + parentComponent, + namespace, + slotScopeIds, + optimized, + rendererInternals + ); + } + }, + hydrate: hydrateSuspense, + create: createSuspenseBoundary, + normalize: normalizeSuspenseChildren +}; +const Suspense = SuspenseImpl ; +function triggerEvent(vnode, name) { + const eventListener = vnode.props && vnode.props[name]; + if (isFunction(eventListener)) { + eventListener(); + } +} +function mountSuspense(vnode, container, anchor, parentComponent, parentSuspense, namespace, slotScopeIds, optimized, rendererInternals) { + const { + p: patch, + o: { createElement } + } = rendererInternals; + const hiddenContainer = createElement("div"); + const suspense = vnode.suspense = createSuspenseBoundary( + vnode, + parentSuspense, + parentComponent, + container, + hiddenContainer, + anchor, + namespace, + slotScopeIds, + optimized, + rendererInternals + ); + patch( + null, + suspense.pendingBranch = vnode.ssContent, + hiddenContainer, + null, + parentComponent, + suspense, + namespace, + slotScopeIds + ); + if (suspense.deps > 0) { + triggerEvent(vnode, "onPending"); + triggerEvent(vnode, "onFallback"); + patch( + null, + vnode.ssFallback, + container, + anchor, + parentComponent, + null, + // fallback tree will not have suspense context + namespace, + slotScopeIds + ); + setActiveBranch(suspense, vnode.ssFallback); + } else { + suspense.resolve(false, true); + } +} +function patchSuspense(n1, n2, container, anchor, parentComponent, namespace, slotScopeIds, optimized, { p: patch, um: unmount, o: { createElement } }) { + const suspense = n2.suspense = n1.suspense; + suspense.vnode = n2; + n2.el = n1.el; + const newBranch = n2.ssContent; + const newFallback = n2.ssFallback; + const { activeBranch, pendingBranch, isInFallback, isHydrating } = suspense; + if (pendingBranch) { + suspense.pendingBranch = newBranch; + if (isSameVNodeType(newBranch, pendingBranch)) { + patch( + pendingBranch, + newBranch, + suspense.hiddenContainer, + null, + parentComponent, + suspense, + namespace, + slotScopeIds, + optimized + ); + if (suspense.deps <= 0) { + suspense.resolve(); + } else if (isInFallback) { + if (!isHydrating) { + patch( + activeBranch, + newFallback, + container, + anchor, + parentComponent, + null, + // fallback tree will not have suspense context + namespace, + slotScopeIds, + optimized + ); + setActiveBranch(suspense, newFallback); + } + } + } else { + suspense.pendingId = suspenseId++; + if (isHydrating) { + suspense.isHydrating = false; + suspense.activeBranch = pendingBranch; + } else { + unmount(pendingBranch, parentComponent, suspense); + } + suspense.deps = 0; + suspense.effects.length = 0; + suspense.hiddenContainer = createElement("div"); + if (isInFallback) { + patch( + null, + newBranch, + suspense.hiddenContainer, + null, + parentComponent, + suspense, + namespace, + slotScopeIds, + optimized + ); + if (suspense.deps <= 0) { + suspense.resolve(); + } else { + patch( + activeBranch, + newFallback, + container, + anchor, + parentComponent, + null, + // fallback tree will not have suspense context + namespace, + slotScopeIds, + optimized + ); + setActiveBranch(suspense, newFallback); + } + } else if (activeBranch && isSameVNodeType(newBranch, activeBranch)) { + patch( + activeBranch, + newBranch, + container, + anchor, + parentComponent, + suspense, + namespace, + slotScopeIds, + optimized + ); + suspense.resolve(true); + } else { + patch( + null, + newBranch, + suspense.hiddenContainer, + null, + parentComponent, + suspense, + namespace, + slotScopeIds, + optimized + ); + if (suspense.deps <= 0) { + suspense.resolve(); + } + } + } + } else { + if (activeBranch && isSameVNodeType(newBranch, activeBranch)) { + patch( + activeBranch, + newBranch, + container, + anchor, + parentComponent, + suspense, + namespace, + slotScopeIds, + optimized + ); + setActiveBranch(suspense, newBranch); + } else { + triggerEvent(n2, "onPending"); + suspense.pendingBranch = newBranch; + if (newBranch.shapeFlag & 512) { + suspense.pendingId = newBranch.component.suspenseId; + } else { + suspense.pendingId = suspenseId++; + } + patch( + null, + newBranch, + suspense.hiddenContainer, + null, + parentComponent, + suspense, + namespace, + slotScopeIds, + optimized + ); + if (suspense.deps <= 0) { + suspense.resolve(); + } else { + const { timeout, pendingId } = suspense; + if (timeout > 0) { + setTimeout(() => { + if (suspense.pendingId === pendingId) { + suspense.fallback(newFallback); + } + }, timeout); + } else if (timeout === 0) { + suspense.fallback(newFallback); + } + } + } + } +} +let hasWarned = false; +function createSuspenseBoundary(vnode, parentSuspense, parentComponent, container, hiddenContainer, anchor, namespace, slotScopeIds, optimized, rendererInternals, isHydrating = false) { + if (!hasWarned) { + hasWarned = true; + console[console.info ? "info" : "log"]( + ` is an experimental feature and its API will likely change.` + ); + } + const { + p: patch, + m: move, + um: unmount, + n: next, + o: { parentNode, remove } + } = rendererInternals; + let parentSuspenseId; + const isSuspensible = isVNodeSuspensible(vnode); + if (isSuspensible) { + if (parentSuspense == null ? void 0 : parentSuspense.pendingBranch) { + parentSuspenseId = parentSuspense.pendingId; + parentSuspense.deps++; + } + } + const timeout = vnode.props ? toNumber(vnode.props.timeout) : void 0; + { + assertNumber(timeout, `Suspense timeout`); + } + const initialAnchor = anchor; + const suspense = { + vnode, + parent: parentSuspense, + parentComponent, + namespace, + container, + hiddenContainer, + deps: 0, + pendingId: suspenseId++, + timeout: typeof timeout === "number" ? timeout : -1, + activeBranch: null, + pendingBranch: null, + isInFallback: !isHydrating, + isHydrating, + isUnmounted: false, + effects: [], + resolve(resume = false, sync = false) { + { + if (!resume && !suspense.pendingBranch) { + throw new Error( + `suspense.resolve() is called without a pending branch.` + ); + } + if (suspense.isUnmounted) { + throw new Error( + `suspense.resolve() is called on an already unmounted suspense boundary.` + ); + } + } + const { + vnode: vnode2, + activeBranch, + pendingBranch, + pendingId, + effects, + parentComponent: parentComponent2, + container: container2 + } = suspense; + let delayEnter = false; + if (suspense.isHydrating) { + suspense.isHydrating = false; + } else if (!resume) { + delayEnter = activeBranch && pendingBranch.transition && pendingBranch.transition.mode === "out-in"; + if (delayEnter) { + activeBranch.transition.afterLeave = () => { + if (pendingId === suspense.pendingId) { + move( + pendingBranch, + container2, + anchor === initialAnchor ? next(activeBranch) : anchor, + 0 + ); + queuePostFlushCb(effects); + } + }; + } + if (activeBranch) { + if (parentNode(activeBranch.el) !== suspense.hiddenContainer) { + anchor = next(activeBranch); + } + unmount(activeBranch, parentComponent2, suspense, true); + } + if (!delayEnter) { + move(pendingBranch, container2, anchor, 0); + } + } + setActiveBranch(suspense, pendingBranch); + suspense.pendingBranch = null; + suspense.isInFallback = false; + let parent = suspense.parent; + let hasUnresolvedAncestor = false; + while (parent) { + if (parent.pendingBranch) { + parent.effects.push(...effects); + hasUnresolvedAncestor = true; + break; + } + parent = parent.parent; + } + if (!hasUnresolvedAncestor && !delayEnter) { + queuePostFlushCb(effects); + } + suspense.effects = []; + if (isSuspensible) { + if (parentSuspense && parentSuspense.pendingBranch && parentSuspenseId === parentSuspense.pendingId) { + parentSuspense.deps--; + if (parentSuspense.deps === 0 && !sync) { + parentSuspense.resolve(); + } + } + } + triggerEvent(vnode2, "onResolve"); + }, + fallback(fallbackVNode) { + if (!suspense.pendingBranch) { + return; + } + const { vnode: vnode2, activeBranch, parentComponent: parentComponent2, container: container2, namespace: namespace2 } = suspense; + triggerEvent(vnode2, "onFallback"); + const anchor2 = next(activeBranch); + const mountFallback = () => { + if (!suspense.isInFallback) { + return; + } + patch( + null, + fallbackVNode, + container2, + anchor2, + parentComponent2, + null, + // fallback tree will not have suspense context + namespace2, + slotScopeIds, + optimized + ); + setActiveBranch(suspense, fallbackVNode); + }; + const delayEnter = fallbackVNode.transition && fallbackVNode.transition.mode === "out-in"; + if (delayEnter) { + activeBranch.transition.afterLeave = mountFallback; + } + suspense.isInFallback = true; + unmount( + activeBranch, + parentComponent2, + null, + // no suspense so unmount hooks fire now + true + // shouldRemove + ); + if (!delayEnter) { + mountFallback(); + } + }, + move(container2, anchor2, type) { + suspense.activeBranch && move(suspense.activeBranch, container2, anchor2, type); + suspense.container = container2; + }, + next() { + return suspense.activeBranch && next(suspense.activeBranch); + }, + registerDep(instance, setupRenderEffect) { + const isInPendingSuspense = !!suspense.pendingBranch; + if (isInPendingSuspense) { + suspense.deps++; + } + const hydratedEl = instance.vnode.el; + instance.asyncDep.catch((err) => { + handleError(err, instance, 0); + }).then((asyncSetupResult) => { + if (instance.isUnmounted || suspense.isUnmounted || suspense.pendingId !== instance.suspenseId) { + return; + } + instance.asyncResolved = true; + const { vnode: vnode2 } = instance; + { + pushWarningContext(vnode2); + } + handleSetupResult(instance, asyncSetupResult, false); + if (hydratedEl) { + vnode2.el = hydratedEl; + } + const placeholder = !hydratedEl && instance.subTree.el; + setupRenderEffect( + instance, + vnode2, + // component may have been moved before resolve. + // if this is not a hydration, instance.subTree will be the comment + // placeholder. + parentNode(hydratedEl || instance.subTree.el), + // anchor will not be used if this is hydration, so only need to + // consider the comment placeholder case. + hydratedEl ? null : next(instance.subTree), + suspense, + namespace, + optimized + ); + if (placeholder) { + remove(placeholder); + } + updateHOCHostEl(instance, vnode2.el); + { + popWarningContext(); + } + if (isInPendingSuspense && --suspense.deps === 0) { + suspense.resolve(); + } + }); + }, + unmount(parentSuspense2, doRemove) { + suspense.isUnmounted = true; + if (suspense.activeBranch) { + unmount( + suspense.activeBranch, + parentComponent, + parentSuspense2, + doRemove + ); + } + if (suspense.pendingBranch) { + unmount( + suspense.pendingBranch, + parentComponent, + parentSuspense2, + doRemove + ); + } + } + }; + return suspense; +} +function hydrateSuspense(node, vnode, parentComponent, parentSuspense, namespace, slotScopeIds, optimized, rendererInternals, hydrateNode) { + const suspense = vnode.suspense = createSuspenseBoundary( + vnode, + parentSuspense, + parentComponent, + node.parentNode, + // eslint-disable-next-line no-restricted-globals + document.createElement("div"), + null, + namespace, + slotScopeIds, + optimized, + rendererInternals, + true + ); + const result = hydrateNode( + node, + suspense.pendingBranch = vnode.ssContent, + parentComponent, + suspense, + slotScopeIds, + optimized + ); + if (suspense.deps === 0) { + suspense.resolve(false, true); + } + return result; +} +function normalizeSuspenseChildren(vnode) { + const { shapeFlag, children } = vnode; + const isSlotChildren = shapeFlag & 32; + vnode.ssContent = normalizeSuspenseSlot( + isSlotChildren ? children.default : children + ); + vnode.ssFallback = isSlotChildren ? normalizeSuspenseSlot(children.fallback) : createVNode(Comment); +} +function normalizeSuspenseSlot(s) { + let block; + if (isFunction(s)) { + const trackBlock = isBlockTreeEnabled && s._c; + if (trackBlock) { + s._d = false; + openBlock(); + } + s = s(); + if (trackBlock) { + s._d = true; + block = currentBlock; + closeBlock(); + } + } + if (isArray(s)) { + const singleChild = filterSingleRoot(s); + if (!singleChild && s.filter((child) => child !== NULL_DYNAMIC_COMPONENT).length > 0) { + warn$1(` slots expect a single root node.`); + } + s = singleChild; + } + s = normalizeVNode(s); + if (block && !s.dynamicChildren) { + s.dynamicChildren = block.filter((c) => c !== s); + } + return s; +} +function queueEffectWithSuspense(fn, suspense) { + if (suspense && suspense.pendingBranch) { + if (isArray(fn)) { + suspense.effects.push(...fn); + } else { + suspense.effects.push(fn); + } + } else { + queuePostFlushCb(fn); + } +} +function setActiveBranch(suspense, branch) { + suspense.activeBranch = branch; + const { vnode, parentComponent } = suspense; + let el = branch.el; + while (!el && branch.component) { + branch = branch.component.subTree; + el = branch.el; + } + vnode.el = el; + if (parentComponent && parentComponent.subTree === vnode) { + parentComponent.vnode.el = el; + updateHOCHostEl(parentComponent, el); + } +} +function isVNodeSuspensible(vnode) { + var _a; + return ((_a = vnode.props) == null ? void 0 : _a.suspensible) != null && vnode.props.suspensible !== false; +} + +const ssrContextKey = Symbol.for("v-scx"); +const useSSRContext = () => { + { + const ctx = inject(ssrContextKey); + if (!ctx) { + warn$1( + `Server rendering context not provided. Make sure to only call useSSRContext() conditionally in the server build.` + ); + } + return ctx; + } +}; + +function watchEffect(effect, options) { + return doWatch(effect, null, options); +} +function watchPostEffect(effect, options) { + return doWatch( + effect, + null, + extend({}, options, { flush: "post" }) + ); +} +function watchSyncEffect(effect, options) { + return doWatch( + effect, + null, + extend({}, options, { flush: "sync" }) + ); +} +const INITIAL_WATCHER_VALUE = {}; +function watch(source, cb, options) { + if (!isFunction(cb)) { + warn$1( + `\`watch(fn, options?)\` signature has been moved to a separate API. Use \`watchEffect(fn, options?)\` instead. \`watch\` now only supports \`watch(source, cb, options?) signature.` + ); + } + return doWatch(source, cb, options); +} +function doWatch(source, cb, { + immediate, + deep, + flush, + once, + onTrack, + onTrigger +} = EMPTY_OBJ) { + if (cb && once) { + const _cb = cb; + cb = (...args) => { + _cb(...args); + unwatch(); + }; + } + if (deep !== void 0 && typeof deep === "number") { + warn$1( + `watch() "deep" option with number value will be used as watch depth in future versions. Please use a boolean instead to avoid potential breakage.` + ); + } + if (!cb) { + if (immediate !== void 0) { + warn$1( + `watch() "immediate" option is only respected when using the watch(source, callback, options?) signature.` + ); + } + if (deep !== void 0) { + warn$1( + `watch() "deep" option is only respected when using the watch(source, callback, options?) signature.` + ); + } + if (once !== void 0) { + warn$1( + `watch() "once" option is only respected when using the watch(source, callback, options?) signature.` + ); + } + } + const warnInvalidSource = (s) => { + warn$1( + `Invalid watch source: `, + s, + `A watch source can only be a getter/effect function, a ref, a reactive object, or an array of these types.` + ); + }; + const instance = currentInstance; + const reactiveGetter = (source2) => deep === true ? source2 : ( + // for deep: false, only traverse root-level properties + traverse(source2, deep === false ? 1 : void 0) + ); + let getter; + let forceTrigger = false; + let isMultiSource = false; + if (isRef(source)) { + getter = () => source.value; + forceTrigger = isShallow(source); + } else if (isReactive(source)) { + getter = () => reactiveGetter(source); + forceTrigger = true; + } else if (isArray(source)) { + isMultiSource = true; + forceTrigger = source.some((s) => isReactive(s) || isShallow(s)); + getter = () => source.map((s) => { + if (isRef(s)) { + return s.value; + } else if (isReactive(s)) { + return reactiveGetter(s); + } else if (isFunction(s)) { + return callWithErrorHandling(s, instance, 2); + } else { + warnInvalidSource(s); + } + }); + } else if (isFunction(source)) { + if (cb) { + getter = () => callWithErrorHandling(source, instance, 2); + } else { + getter = () => { + if (cleanup) { + cleanup(); + } + return callWithAsyncErrorHandling( + source, + instance, + 3, + [onCleanup] + ); + }; + } + } else { + getter = NOOP; + warnInvalidSource(source); + } + if (cb && deep) { + const baseGetter = getter; + getter = () => traverse(baseGetter()); + } + let cleanup; + let onCleanup = (fn) => { + cleanup = effect.onStop = () => { + callWithErrorHandling(fn, instance, 4); + cleanup = effect.onStop = void 0; + }; + }; + let oldValue = isMultiSource ? new Array(source.length).fill(INITIAL_WATCHER_VALUE) : INITIAL_WATCHER_VALUE; + const job = () => { + if (!effect.active || !effect.dirty) { + return; + } + if (cb) { + const newValue = effect.run(); + if (deep || forceTrigger || (isMultiSource ? newValue.some((v, i) => hasChanged(v, oldValue[i])) : hasChanged(newValue, oldValue)) || false) { + if (cleanup) { + cleanup(); + } + callWithAsyncErrorHandling(cb, instance, 3, [ + newValue, + // pass undefined as the old value when it's changed for the first time + oldValue === INITIAL_WATCHER_VALUE ? void 0 : isMultiSource && oldValue[0] === INITIAL_WATCHER_VALUE ? [] : oldValue, + onCleanup + ]); + oldValue = newValue; + } + } else { + effect.run(); + } + }; + job.allowRecurse = !!cb; + let scheduler; + if (flush === "sync") { + scheduler = job; + } else if (flush === "post") { + scheduler = () => queuePostRenderEffect(job, instance && instance.suspense); + } else { + job.pre = true; + if (instance) + job.id = instance.uid; + scheduler = () => queueJob(job); + } + const effect = new ReactiveEffect(getter, NOOP, scheduler); + const scope = getCurrentScope(); + const unwatch = () => { + effect.stop(); + if (scope) { + remove(scope.effects, effect); + } + }; + { + effect.onTrack = onTrack; + effect.onTrigger = onTrigger; + } + if (cb) { + if (immediate) { + job(); + } else { + oldValue = effect.run(); + } + } else if (flush === "post") { + queuePostRenderEffect( + effect.run.bind(effect), + instance && instance.suspense + ); + } else { + effect.run(); + } + return unwatch; +} +function instanceWatch(source, value, options) { + const publicThis = this.proxy; + const getter = isString(source) ? source.includes(".") ? createPathGetter(publicThis, source) : () => publicThis[source] : source.bind(publicThis, publicThis); + let cb; + if (isFunction(value)) { + cb = value; + } else { + cb = value.handler; + options = value; + } + const reset = setCurrentInstance(this); + const res = doWatch(getter, cb.bind(publicThis), options); + reset(); + return res; +} +function createPathGetter(ctx, path) { + const segments = path.split("."); + return () => { + let cur = ctx; + for (let i = 0; i < segments.length && cur; i++) { + cur = cur[segments[i]]; + } + return cur; + }; +} +function traverse(value, depth, currentDepth = 0, seen) { + if (!isObject(value) || value["__v_skip"]) { + return value; + } + if (depth && depth > 0) { + if (currentDepth >= depth) { + return value; + } + currentDepth++; + } + seen = seen || /* @__PURE__ */ new Set(); + if (seen.has(value)) { + return value; + } + seen.add(value); + if (isRef(value)) { + traverse(value.value, depth, currentDepth, seen); + } else if (isArray(value)) { + for (let i = 0; i < value.length; i++) { + traverse(value[i], depth, currentDepth, seen); + } + } else if (isSet(value) || isMap(value)) { + value.forEach((v) => { + traverse(v, depth, currentDepth, seen); + }); + } else if (isPlainObject(value)) { + for (const key in value) { + traverse(value[key], depth, currentDepth, seen); + } + } + return value; +} + +function validateDirectiveName(name) { + if (isBuiltInDirective(name)) { + warn$1("Do not use built-in directive ids as custom directive id: " + name); + } +} +function withDirectives(vnode, directives) { + if (currentRenderingInstance === null) { + warn$1(`withDirectives can only be used inside render functions.`); + return vnode; + } + const instance = getExposeProxy(currentRenderingInstance) || currentRenderingInstance.proxy; + const bindings = vnode.dirs || (vnode.dirs = []); + for (let i = 0; i < directives.length; i++) { + let [dir, value, arg, modifiers = EMPTY_OBJ] = directives[i]; + if (dir) { + if (isFunction(dir)) { + dir = { + mounted: dir, + updated: dir + }; + } + if (dir.deep) { + traverse(value); + } + bindings.push({ + dir, + instance, + value, + oldValue: void 0, + arg, + modifiers + }); + } + } + return vnode; +} +function invokeDirectiveHook(vnode, prevVNode, instance, name) { + const bindings = vnode.dirs; + const oldBindings = prevVNode && prevVNode.dirs; + for (let i = 0; i < bindings.length; i++) { + const binding = bindings[i]; + if (oldBindings) { + binding.oldValue = oldBindings[i].value; + } + let hook = binding.dir[name]; + if (hook) { + pauseTracking(); + callWithAsyncErrorHandling(hook, instance, 8, [ + vnode.el, + binding, + vnode, + prevVNode + ]); + resetTracking(); + } + } +} + +const leaveCbKey = Symbol("_leaveCb"); +const enterCbKey$1 = Symbol("_enterCb"); +function useTransitionState() { + const state = { + isMounted: false, + isLeaving: false, + isUnmounting: false, + leavingVNodes: /* @__PURE__ */ new Map() + }; + onMounted(() => { + state.isMounted = true; + }); + onBeforeUnmount(() => { + state.isUnmounting = true; + }); + return state; +} +const TransitionHookValidator = [Function, Array]; +const BaseTransitionPropsValidators = { + mode: String, + appear: Boolean, + persisted: Boolean, + // enter + onBeforeEnter: TransitionHookValidator, + onEnter: TransitionHookValidator, + onAfterEnter: TransitionHookValidator, + onEnterCancelled: TransitionHookValidator, + // leave + onBeforeLeave: TransitionHookValidator, + onLeave: TransitionHookValidator, + onAfterLeave: TransitionHookValidator, + onLeaveCancelled: TransitionHookValidator, + // appear + onBeforeAppear: TransitionHookValidator, + onAppear: TransitionHookValidator, + onAfterAppear: TransitionHookValidator, + onAppearCancelled: TransitionHookValidator +}; +const BaseTransitionImpl = { + name: `BaseTransition`, + props: BaseTransitionPropsValidators, + setup(props, { slots }) { + const instance = getCurrentInstance(); + const state = useTransitionState(); + let prevTransitionKey; + return () => { + const children = slots.default && getTransitionRawChildren(slots.default(), true); + if (!children || !children.length) { + return; + } + let child = children[0]; + if (children.length > 1) { + let hasFound = false; + for (const c of children) { + if (c.type !== Comment) { + if (hasFound) { + warn$1( + " can only be used on a single element or component. Use for lists." + ); + break; + } + child = c; + hasFound = true; + } + } + } + const rawProps = toRaw(props); + const { mode } = rawProps; + if (mode && mode !== "in-out" && mode !== "out-in" && mode !== "default") { + warn$1(`invalid mode: ${mode}`); + } + if (state.isLeaving) { + return emptyPlaceholder(child); + } + const innerChild = getKeepAliveChild(child); + if (!innerChild) { + return emptyPlaceholder(child); + } + const enterHooks = resolveTransitionHooks( + innerChild, + rawProps, + state, + instance + ); + setTransitionHooks(innerChild, enterHooks); + const oldChild = instance.subTree; + const oldInnerChild = oldChild && getKeepAliveChild(oldChild); + let transitionKeyChanged = false; + const { getTransitionKey } = innerChild.type; + if (getTransitionKey) { + const key = getTransitionKey(); + if (prevTransitionKey === void 0) { + prevTransitionKey = key; + } else if (key !== prevTransitionKey) { + prevTransitionKey = key; + transitionKeyChanged = true; + } + } + if (oldInnerChild && oldInnerChild.type !== Comment && (!isSameVNodeType(innerChild, oldInnerChild) || transitionKeyChanged)) { + const leavingHooks = resolveTransitionHooks( + oldInnerChild, + rawProps, + state, + instance + ); + setTransitionHooks(oldInnerChild, leavingHooks); + if (mode === "out-in") { + state.isLeaving = true; + leavingHooks.afterLeave = () => { + state.isLeaving = false; + if (instance.update.active !== false) { + instance.effect.dirty = true; + instance.update(); + } + }; + return emptyPlaceholder(child); + } else if (mode === "in-out" && innerChild.type !== Comment) { + leavingHooks.delayLeave = (el, earlyRemove, delayedLeave) => { + const leavingVNodesCache = getLeavingNodesForType( + state, + oldInnerChild + ); + leavingVNodesCache[String(oldInnerChild.key)] = oldInnerChild; + el[leaveCbKey] = () => { + earlyRemove(); + el[leaveCbKey] = void 0; + delete enterHooks.delayedLeave; + }; + enterHooks.delayedLeave = delayedLeave; + }; + } + } + return child; + }; + } +}; +const BaseTransition = BaseTransitionImpl; +function getLeavingNodesForType(state, vnode) { + const { leavingVNodes } = state; + let leavingVNodesCache = leavingVNodes.get(vnode.type); + if (!leavingVNodesCache) { + leavingVNodesCache = /* @__PURE__ */ Object.create(null); + leavingVNodes.set(vnode.type, leavingVNodesCache); + } + return leavingVNodesCache; +} +function resolveTransitionHooks(vnode, props, state, instance) { + const { + appear, + mode, + persisted = false, + onBeforeEnter, + onEnter, + onAfterEnter, + onEnterCancelled, + onBeforeLeave, + onLeave, + onAfterLeave, + onLeaveCancelled, + onBeforeAppear, + onAppear, + onAfterAppear, + onAppearCancelled + } = props; + const key = String(vnode.key); + const leavingVNodesCache = getLeavingNodesForType(state, vnode); + const callHook = (hook, args) => { + hook && callWithAsyncErrorHandling( + hook, + instance, + 9, + args + ); + }; + const callAsyncHook = (hook, args) => { + const done = args[1]; + callHook(hook, args); + if (isArray(hook)) { + if (hook.every((hook2) => hook2.length <= 1)) + done(); + } else if (hook.length <= 1) { + done(); + } + }; + const hooks = { + mode, + persisted, + beforeEnter(el) { + let hook = onBeforeEnter; + if (!state.isMounted) { + if (appear) { + hook = onBeforeAppear || onBeforeEnter; + } else { + return; + } + } + if (el[leaveCbKey]) { + el[leaveCbKey]( + true + /* cancelled */ + ); + } + const leavingVNode = leavingVNodesCache[key]; + if (leavingVNode && isSameVNodeType(vnode, leavingVNode) && leavingVNode.el[leaveCbKey]) { + leavingVNode.el[leaveCbKey](); + } + callHook(hook, [el]); + }, + enter(el) { + let hook = onEnter; + let afterHook = onAfterEnter; + let cancelHook = onEnterCancelled; + if (!state.isMounted) { + if (appear) { + hook = onAppear || onEnter; + afterHook = onAfterAppear || onAfterEnter; + cancelHook = onAppearCancelled || onEnterCancelled; + } else { + return; + } + } + let called = false; + const done = el[enterCbKey$1] = (cancelled) => { + if (called) + return; + called = true; + if (cancelled) { + callHook(cancelHook, [el]); + } else { + callHook(afterHook, [el]); + } + if (hooks.delayedLeave) { + hooks.delayedLeave(); + } + el[enterCbKey$1] = void 0; + }; + if (hook) { + callAsyncHook(hook, [el, done]); + } else { + done(); + } + }, + leave(el, remove) { + const key2 = String(vnode.key); + if (el[enterCbKey$1]) { + el[enterCbKey$1]( + true + /* cancelled */ + ); + } + if (state.isUnmounting) { + return remove(); + } + callHook(onBeforeLeave, [el]); + let called = false; + const done = el[leaveCbKey] = (cancelled) => { + if (called) + return; + called = true; + remove(); + if (cancelled) { + callHook(onLeaveCancelled, [el]); + } else { + callHook(onAfterLeave, [el]); + } + el[leaveCbKey] = void 0; + if (leavingVNodesCache[key2] === vnode) { + delete leavingVNodesCache[key2]; + } + }; + leavingVNodesCache[key2] = vnode; + if (onLeave) { + callAsyncHook(onLeave, [el, done]); + } else { + done(); + } + }, + clone(vnode2) { + return resolveTransitionHooks(vnode2, props, state, instance); + } + }; + return hooks; +} +function emptyPlaceholder(vnode) { + if (isKeepAlive(vnode)) { + vnode = cloneVNode(vnode); + vnode.children = null; + return vnode; + } +} +function getKeepAliveChild(vnode) { + return isKeepAlive(vnode) ? ( + // #7121 ensure get the child component subtree in case + // it's been replaced during HMR + vnode.component ? vnode.component.subTree : vnode.children ? vnode.children[0] : void 0 + ) : vnode; +} +function setTransitionHooks(vnode, hooks) { + if (vnode.shapeFlag & 6 && vnode.component) { + setTransitionHooks(vnode.component.subTree, hooks); + } else if (vnode.shapeFlag & 128) { + vnode.ssContent.transition = hooks.clone(vnode.ssContent); + vnode.ssFallback.transition = hooks.clone(vnode.ssFallback); + } else { + vnode.transition = hooks; + } +} +function getTransitionRawChildren(children, keepComment = false, parentKey) { + let ret = []; + let keyedFragmentCount = 0; + for (let i = 0; i < children.length; i++) { + let child = children[i]; + const key = parentKey == null ? child.key : String(parentKey) + String(child.key != null ? child.key : i); + if (child.type === Fragment) { + if (child.patchFlag & 128) + keyedFragmentCount++; + ret = ret.concat( + getTransitionRawChildren(child.children, keepComment, key) + ); + } else if (keepComment || child.type !== Comment) { + ret.push(key != null ? cloneVNode(child, { key }) : child); + } + } + if (keyedFragmentCount > 1) { + for (let i = 0; i < ret.length; i++) { + ret[i].patchFlag = -2; + } + } + return ret; +} + +/*! #__NO_SIDE_EFFECTS__ */ +// @__NO_SIDE_EFFECTS__ +function defineComponent(options, extraOptions) { + return isFunction(options) ? ( + // #8326: extend call and options.name access are considered side-effects + // by Rollup, so we have to wrap it in a pure-annotated IIFE. + /* @__PURE__ */ (() => extend({ name: options.name }, extraOptions, { setup: options }))() + ) : options; +} + +const isAsyncWrapper = (i) => !!i.type.__asyncLoader; +/*! #__NO_SIDE_EFFECTS__ */ +// @__NO_SIDE_EFFECTS__ +function defineAsyncComponent(source) { + if (isFunction(source)) { + source = { loader: source }; + } + const { + loader, + loadingComponent, + errorComponent, + delay = 200, + timeout, + // undefined = never times out + suspensible = true, + onError: userOnError + } = source; + let pendingRequest = null; + let resolvedComp; + let retries = 0; + const retry = () => { + retries++; + pendingRequest = null; + return load(); + }; + const load = () => { + let thisRequest; + return pendingRequest || (thisRequest = pendingRequest = loader().catch((err) => { + err = err instanceof Error ? err : new Error(String(err)); + if (userOnError) { + return new Promise((resolve, reject) => { + const userRetry = () => resolve(retry()); + const userFail = () => reject(err); + userOnError(err, userRetry, userFail, retries + 1); + }); + } else { + throw err; + } + }).then((comp) => { + if (thisRequest !== pendingRequest && pendingRequest) { + return pendingRequest; + } + if (!comp) { + warn$1( + `Async component loader resolved to undefined. If you are using retry(), make sure to return its return value.` + ); + } + if (comp && (comp.__esModule || comp[Symbol.toStringTag] === "Module")) { + comp = comp.default; + } + if (comp && !isObject(comp) && !isFunction(comp)) { + throw new Error(`Invalid async component load result: ${comp}`); + } + resolvedComp = comp; + return comp; + })); + }; + return defineComponent({ + name: "AsyncComponentWrapper", + __asyncLoader: load, + get __asyncResolved() { + return resolvedComp; + }, + setup() { + const instance = currentInstance; + if (resolvedComp) { + return () => createInnerComp(resolvedComp, instance); + } + const onError = (err) => { + pendingRequest = null; + handleError( + err, + instance, + 13, + !errorComponent + ); + }; + if (suspensible && instance.suspense || false) { + return load().then((comp) => { + return () => createInnerComp(comp, instance); + }).catch((err) => { + onError(err); + return () => errorComponent ? createVNode(errorComponent, { + error: err + }) : null; + }); + } + const loaded = ref(false); + const error = ref(); + const delayed = ref(!!delay); + if (delay) { + setTimeout(() => { + delayed.value = false; + }, delay); + } + if (timeout != null) { + setTimeout(() => { + if (!loaded.value && !error.value) { + const err = new Error( + `Async component timed out after ${timeout}ms.` + ); + onError(err); + error.value = err; + } + }, timeout); + } + load().then(() => { + loaded.value = true; + if (instance.parent && isKeepAlive(instance.parent.vnode)) { + instance.parent.effect.dirty = true; + queueJob(instance.parent.update); + } + }).catch((err) => { + onError(err); + error.value = err; + }); + return () => { + if (loaded.value && resolvedComp) { + return createInnerComp(resolvedComp, instance); + } else if (error.value && errorComponent) { + return createVNode(errorComponent, { + error: error.value + }); + } else if (loadingComponent && !delayed.value) { + return createVNode(loadingComponent); + } + }; + } + }); +} +function createInnerComp(comp, parent) { + const { ref: ref2, props, children, ce } = parent.vnode; + const vnode = createVNode(comp, props, children); + vnode.ref = ref2; + vnode.ce = ce; + delete parent.vnode.ce; + return vnode; +} + +const isKeepAlive = (vnode) => vnode.type.__isKeepAlive; +const KeepAliveImpl = { + name: `KeepAlive`, + // Marker for special handling inside the renderer. We are not using a === + // check directly on KeepAlive in the renderer, because importing it directly + // would prevent it from being tree-shaken. + __isKeepAlive: true, + props: { + include: [String, RegExp, Array], + exclude: [String, RegExp, Array], + max: [String, Number] + }, + setup(props, { slots }) { + const instance = getCurrentInstance(); + const sharedContext = instance.ctx; + const cache = /* @__PURE__ */ new Map(); + const keys = /* @__PURE__ */ new Set(); + let current = null; + { + instance.__v_cache = cache; + } + const parentSuspense = instance.suspense; + const { + renderer: { + p: patch, + m: move, + um: _unmount, + o: { createElement } + } + } = sharedContext; + const storageContainer = createElement("div"); + sharedContext.activate = (vnode, container, anchor, namespace, optimized) => { + const instance2 = vnode.component; + move(vnode, container, anchor, 0, parentSuspense); + patch( + instance2.vnode, + vnode, + container, + anchor, + instance2, + parentSuspense, + namespace, + vnode.slotScopeIds, + optimized + ); + queuePostRenderEffect(() => { + instance2.isDeactivated = false; + if (instance2.a) { + invokeArrayFns(instance2.a); + } + const vnodeHook = vnode.props && vnode.props.onVnodeMounted; + if (vnodeHook) { + invokeVNodeHook(vnodeHook, instance2.parent, vnode); + } + }, parentSuspense); + { + devtoolsComponentAdded(instance2); + } + }; + sharedContext.deactivate = (vnode) => { + const instance2 = vnode.component; + move(vnode, storageContainer, null, 1, parentSuspense); + queuePostRenderEffect(() => { + if (instance2.da) { + invokeArrayFns(instance2.da); + } + const vnodeHook = vnode.props && vnode.props.onVnodeUnmounted; + if (vnodeHook) { + invokeVNodeHook(vnodeHook, instance2.parent, vnode); + } + instance2.isDeactivated = true; + }, parentSuspense); + { + devtoolsComponentAdded(instance2); + } + }; + function unmount(vnode) { + resetShapeFlag(vnode); + _unmount(vnode, instance, parentSuspense, true); + } + function pruneCache(filter) { + cache.forEach((vnode, key) => { + const name = getComponentName(vnode.type); + if (name && (!filter || !filter(name))) { + pruneCacheEntry(key); + } + }); + } + function pruneCacheEntry(key) { + const cached = cache.get(key); + if (!current || !isSameVNodeType(cached, current)) { + unmount(cached); + } else if (current) { + resetShapeFlag(current); + } + cache.delete(key); + keys.delete(key); + } + watch( + () => [props.include, props.exclude], + ([include, exclude]) => { + include && pruneCache((name) => matches(include, name)); + exclude && pruneCache((name) => !matches(exclude, name)); + }, + // prune post-render after `current` has been updated + { flush: "post", deep: true } + ); + let pendingCacheKey = null; + const cacheSubtree = () => { + if (pendingCacheKey != null) { + cache.set(pendingCacheKey, getInnerChild(instance.subTree)); + } + }; + onMounted(cacheSubtree); + onUpdated(cacheSubtree); + onBeforeUnmount(() => { + cache.forEach((cached) => { + const { subTree, suspense } = instance; + const vnode = getInnerChild(subTree); + if (cached.type === vnode.type && cached.key === vnode.key) { + resetShapeFlag(vnode); + const da = vnode.component.da; + da && queuePostRenderEffect(da, suspense); + return; + } + unmount(cached); + }); + }); + return () => { + pendingCacheKey = null; + if (!slots.default) { + return null; + } + const children = slots.default(); + const rawVNode = children[0]; + if (children.length > 1) { + { + warn$1(`KeepAlive should contain exactly one component child.`); + } + current = null; + return children; + } else if (!isVNode(rawVNode) || !(rawVNode.shapeFlag & 4) && !(rawVNode.shapeFlag & 128)) { + current = null; + return rawVNode; + } + let vnode = getInnerChild(rawVNode); + const comp = vnode.type; + const name = getComponentName( + isAsyncWrapper(vnode) ? vnode.type.__asyncResolved || {} : comp + ); + const { include, exclude, max } = props; + if (include && (!name || !matches(include, name)) || exclude && name && matches(exclude, name)) { + current = vnode; + return rawVNode; + } + const key = vnode.key == null ? comp : vnode.key; + const cachedVNode = cache.get(key); + if (vnode.el) { + vnode = cloneVNode(vnode); + if (rawVNode.shapeFlag & 128) { + rawVNode.ssContent = vnode; + } + } + pendingCacheKey = key; + if (cachedVNode) { + vnode.el = cachedVNode.el; + vnode.component = cachedVNode.component; + if (vnode.transition) { + setTransitionHooks(vnode, vnode.transition); + } + vnode.shapeFlag |= 512; + keys.delete(key); + keys.add(key); + } else { + keys.add(key); + if (max && keys.size > parseInt(max, 10)) { + pruneCacheEntry(keys.values().next().value); + } + } + vnode.shapeFlag |= 256; + current = vnode; + return isSuspense(rawVNode.type) ? rawVNode : vnode; + }; + } +}; +const KeepAlive = KeepAliveImpl; +function matches(pattern, name) { + if (isArray(pattern)) { + return pattern.some((p) => matches(p, name)); + } else if (isString(pattern)) { + return pattern.split(",").includes(name); + } else if (isRegExp(pattern)) { + return pattern.test(name); + } + return false; +} +function onActivated(hook, target) { + registerKeepAliveHook(hook, "a", target); +} +function onDeactivated(hook, target) { + registerKeepAliveHook(hook, "da", target); +} +function registerKeepAliveHook(hook, type, target = currentInstance) { + const wrappedHook = hook.__wdc || (hook.__wdc = () => { + let current = target; + while (current) { + if (current.isDeactivated) { + return; + } + current = current.parent; + } + return hook(); + }); + injectHook(type, wrappedHook, target); + if (target) { + let current = target.parent; + while (current && current.parent) { + if (isKeepAlive(current.parent.vnode)) { + injectToKeepAliveRoot(wrappedHook, type, target, current); + } + current = current.parent; + } + } +} +function injectToKeepAliveRoot(hook, type, target, keepAliveRoot) { + const injected = injectHook( + type, + hook, + keepAliveRoot, + true + /* prepend */ + ); + onUnmounted(() => { + remove(keepAliveRoot[type], injected); + }, target); +} +function resetShapeFlag(vnode) { + vnode.shapeFlag &= ~256; + vnode.shapeFlag &= ~512; +} +function getInnerChild(vnode) { + return vnode.shapeFlag & 128 ? vnode.ssContent : vnode; +} + +function injectHook(type, hook, target = currentInstance, prepend = false) { + if (target) { + const hooks = target[type] || (target[type] = []); + const wrappedHook = hook.__weh || (hook.__weh = (...args) => { + if (target.isUnmounted) { + return; + } + pauseTracking(); + const reset = setCurrentInstance(target); + const res = callWithAsyncErrorHandling(hook, target, type, args); + reset(); + resetTracking(); + return res; + }); + if (prepend) { + hooks.unshift(wrappedHook); + } else { + hooks.push(wrappedHook); + } + return wrappedHook; + } else { + const apiName = toHandlerKey(ErrorTypeStrings$1[type].replace(/ hook$/, "")); + warn$1( + `${apiName} is called when there is no active component instance to be associated with. Lifecycle injection APIs can only be used during execution of setup().` + (` If you are using async setup(), make sure to register lifecycle hooks before the first await statement.` ) + ); + } +} +const createHook = (lifecycle) => (hook, target = currentInstance) => ( + // post-create lifecycle registrations are noops during SSR (except for serverPrefetch) + (!isInSSRComponentSetup || lifecycle === "sp") && injectHook(lifecycle, (...args) => hook(...args), target) +); +const onBeforeMount = createHook("bm"); +const onMounted = createHook("m"); +const onBeforeUpdate = createHook("bu"); +const onUpdated = createHook("u"); +const onBeforeUnmount = createHook("bum"); +const onUnmounted = createHook("um"); +const onServerPrefetch = createHook("sp"); +const onRenderTriggered = createHook( + "rtg" +); +const onRenderTracked = createHook( + "rtc" +); +function onErrorCaptured(hook, target = currentInstance) { + injectHook("ec", hook, target); +} + +function renderList(source, renderItem, cache, index) { + let ret; + const cached = cache && cache[index]; + if (isArray(source) || isString(source)) { + ret = new Array(source.length); + for (let i = 0, l = source.length; i < l; i++) { + ret[i] = renderItem(source[i], i, void 0, cached && cached[i]); + } + } else if (typeof source === "number") { + if (!Number.isInteger(source)) { + warn$1(`The v-for range expect an integer value but got ${source}.`); + } + ret = new Array(source); + for (let i = 0; i < source; i++) { + ret[i] = renderItem(i + 1, i, void 0, cached && cached[i]); + } + } else if (isObject(source)) { + if (source[Symbol.iterator]) { + ret = Array.from( + source, + (item, i) => renderItem(item, i, void 0, cached && cached[i]) + ); + } else { + const keys = Object.keys(source); + ret = new Array(keys.length); + for (let i = 0, l = keys.length; i < l; i++) { + const key = keys[i]; + ret[i] = renderItem(source[key], key, i, cached && cached[i]); + } + } + } else { + ret = []; + } + if (cache) { + cache[index] = ret; + } + return ret; +} + +function createSlots(slots, dynamicSlots) { + for (let i = 0; i < dynamicSlots.length; i++) { + const slot = dynamicSlots[i]; + if (isArray(slot)) { + for (let j = 0; j < slot.length; j++) { + slots[slot[j].name] = slot[j].fn; + } + } else if (slot) { + slots[slot.name] = slot.key ? (...args) => { + const res = slot.fn(...args); + if (res) + res.key = slot.key; + return res; + } : slot.fn; + } + } + return slots; +} + +function renderSlot(slots, name, props = {}, fallback, noSlotted) { + if (currentRenderingInstance.isCE || currentRenderingInstance.parent && isAsyncWrapper(currentRenderingInstance.parent) && currentRenderingInstance.parent.isCE) { + if (name !== "default") + props.name = name; + return createVNode("slot", props, fallback && fallback()); + } + let slot = slots[name]; + if (slot && slot.length > 1) { + warn$1( + `SSR-optimized slot function detected in a non-SSR-optimized render function. You need to mark this component with $dynamic-slots in the parent template.` + ); + slot = () => []; + } + if (slot && slot._c) { + slot._d = false; + } + openBlock(); + const validSlotContent = slot && ensureValidVNode(slot(props)); + const rendered = createBlock( + Fragment, + { + key: props.key || // slot content array of a dynamic conditional slot may have a branch + // key attached in the `createSlots` helper, respect that + validSlotContent && validSlotContent.key || `_${name}` + }, + validSlotContent || (fallback ? fallback() : []), + validSlotContent && slots._ === 1 ? 64 : -2 + ); + if (!noSlotted && rendered.scopeId) { + rendered.slotScopeIds = [rendered.scopeId + "-s"]; + } + if (slot && slot._c) { + slot._d = true; + } + return rendered; +} +function ensureValidVNode(vnodes) { + return vnodes.some((child) => { + if (!isVNode(child)) + return true; + if (child.type === Comment) + return false; + if (child.type === Fragment && !ensureValidVNode(child.children)) + return false; + return true; + }) ? vnodes : null; +} + +function toHandlers(obj, preserveCaseIfNecessary) { + const ret = {}; + if (!isObject(obj)) { + warn$1(`v-on with no argument expects an object value.`); + return ret; + } + for (const key in obj) { + ret[preserveCaseIfNecessary && /[A-Z]/.test(key) ? `on:${key}` : toHandlerKey(key)] = obj[key]; + } + return ret; +} + +const getPublicInstance = (i) => { + if (!i) + return null; + if (isStatefulComponent(i)) + return getExposeProxy(i) || i.proxy; + return getPublicInstance(i.parent); +}; +const publicPropertiesMap = ( + // Move PURE marker to new line to workaround compiler discarding it + // due to type annotation + /* @__PURE__ */ extend(/* @__PURE__ */ Object.create(null), { + $: (i) => i, + $el: (i) => i.vnode.el, + $data: (i) => i.data, + $props: (i) => shallowReadonly(i.props) , + $attrs: (i) => shallowReadonly(i.attrs) , + $slots: (i) => shallowReadonly(i.slots) , + $refs: (i) => shallowReadonly(i.refs) , + $parent: (i) => getPublicInstance(i.parent), + $root: (i) => getPublicInstance(i.root), + $emit: (i) => i.emit, + $options: (i) => resolveMergedOptions(i) , + $forceUpdate: (i) => i.f || (i.f = () => { + i.effect.dirty = true; + queueJob(i.update); + }), + $nextTick: (i) => i.n || (i.n = nextTick.bind(i.proxy)), + $watch: (i) => instanceWatch.bind(i) + }) +); +const isReservedPrefix = (key) => key === "_" || key === "$"; +const hasSetupBinding = (state, key) => state !== EMPTY_OBJ && !state.__isScriptSetup && hasOwn(state, key); +const PublicInstanceProxyHandlers = { + get({ _: instance }, key) { + const { ctx, setupState, data, props, accessCache, type, appContext } = instance; + if (key === "__isVue") { + return true; + } + let normalizedProps; + if (key[0] !== "$") { + const n = accessCache[key]; + if (n !== void 0) { + switch (n) { + case 1 /* SETUP */: + return setupState[key]; + case 2 /* DATA */: + return data[key]; + case 4 /* CONTEXT */: + return ctx[key]; + case 3 /* PROPS */: + return props[key]; + } + } else if (hasSetupBinding(setupState, key)) { + accessCache[key] = 1 /* SETUP */; + return setupState[key]; + } else if (data !== EMPTY_OBJ && hasOwn(data, key)) { + accessCache[key] = 2 /* DATA */; + return data[key]; + } else if ( + // only cache other properties when instance has declared (thus stable) + // props + (normalizedProps = instance.propsOptions[0]) && hasOwn(normalizedProps, key) + ) { + accessCache[key] = 3 /* PROPS */; + return props[key]; + } else if (ctx !== EMPTY_OBJ && hasOwn(ctx, key)) { + accessCache[key] = 4 /* CONTEXT */; + return ctx[key]; + } else if (shouldCacheAccess) { + accessCache[key] = 0 /* OTHER */; + } + } + const publicGetter = publicPropertiesMap[key]; + let cssModule, globalProperties; + if (publicGetter) { + if (key === "$attrs") { + track(instance, "get", key); + markAttrsAccessed(); + } else if (key === "$slots") { + track(instance, "get", key); + } + return publicGetter(instance); + } else if ( + // css module (injected by vue-loader) + (cssModule = type.__cssModules) && (cssModule = cssModule[key]) + ) { + return cssModule; + } else if (ctx !== EMPTY_OBJ && hasOwn(ctx, key)) { + accessCache[key] = 4 /* CONTEXT */; + return ctx[key]; + } else if ( + // global properties + globalProperties = appContext.config.globalProperties, hasOwn(globalProperties, key) + ) { + { + return globalProperties[key]; + } + } else if (currentRenderingInstance && (!isString(key) || // #1091 avoid internal isRef/isVNode checks on component instance leading + // to infinite warning loop + key.indexOf("__v") !== 0)) { + if (data !== EMPTY_OBJ && isReservedPrefix(key[0]) && hasOwn(data, key)) { + warn$1( + `Property ${JSON.stringify( + key + )} must be accessed via $data because it starts with a reserved character ("$" or "_") and is not proxied on the render context.` + ); + } else if (instance === currentRenderingInstance) { + warn$1( + `Property ${JSON.stringify(key)} was accessed during render but is not defined on instance.` + ); + } + } + }, + set({ _: instance }, key, value) { + const { data, setupState, ctx } = instance; + if (hasSetupBinding(setupState, key)) { + setupState[key] = value; + return true; + } else if (setupState.__isScriptSetup && hasOwn(setupState, key)) { + warn$1(`Cannot mutate + + + + + + + + + + + + + + + {{navigation}} + +
+
+ {{#side_navigation}} + {{side_navigation}} + +
+ {{/side_navigation}} + {{^side_navigation}}
{{/side_navigation}} +
+ +
+ + {{content}} +
+ +
+
+ + + + + + + diff --git a/hal-core/resources/web/main_nav.tmpl b/hal-core/resources/web/main_nav.tmpl new file mode 100644 index 00000000..a62fb405 --- /dev/null +++ b/hal-core/resources/web/main_nav.tmpl @@ -0,0 +1,65 @@ + \ No newline at end of file diff --git a/hal-core/resources/web/main_nav_side.tmpl b/hal-core/resources/web/main_nav_side.tmpl new file mode 100644 index 00000000..346a658b --- /dev/null +++ b/hal-core/resources/web/main_nav_side.tmpl @@ -0,0 +1,10 @@ + + diff --git a/hal-core/resources/web/map.tmpl b/hal-core/resources/web/map.tmpl new file mode 100644 index 00000000..c38ae6a4 --- /dev/null +++ b/hal-core/resources/web/map.tmpl @@ -0,0 +1,82 @@ + + +
+ +
+ +
+ + + +
+
+ +
+ + +
+
+
+ +
+
+ Icons downloaded from icons8.com +
+
+ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/hal-core/resources/web/plugin_config.tmpl b/hal-core/resources/web/plugin_config.tmpl new file mode 100644 index 00000000..e2f5375a --- /dev/null +++ b/hal-core/resources/web/plugin_config.tmpl @@ -0,0 +1,111 @@ +

Plugins

+ +
+
+
Plugin Administration
+
+ + + + + + + + + {{#plugins}} + + + + + + + {{/plugins}} +
NameVersionDescriptionEnable
{{.getName()}}{{.getVersion()}}{{#.getDescription()}}{{.getDescription()}}{{/.getDescription()}} +
+ + + +
+ +
+
+
+
+
+
+ +
+
+
Controllers
+
+ + + + + + + + + {{#controllers}} + + + + + + + {{/controllers}} +
NameStatusRegistered DevicesActions
{{.getClass().getName()}} + {{#.isAvailable()}}Running{{/.isAvailable()}} + {{^.isAvailable()}}Down{{/.isAvailable()}} + {{.size()}} + {{#.isScannable()}} +
+
+ + + + {{#.isScanning()}} + + {{/.isScanning()}} + {{^.isScanning()}} + + {{/.isScanning()}} +
+ {{/.isScannable()}} +
+
+
+
+
+ +
+
+
Daemons
+
+ + + + + + {{#daemons}} + + + + {{/daemons}} +
Name
{{.getClass().getName()}}
+
+
+
+ + \ No newline at end of file diff --git a/hal-core/resources/web/property_config.tmpl b/hal-core/resources/web/property_config.tmpl new file mode 100644 index 00000000..74154ee2 --- /dev/null +++ b/hal-core/resources/web/property_config.tmpl @@ -0,0 +1,24 @@ +

Hal Properties

+ +
+
+
Registered properties
+
+ + + + + + + + {{#properties}} + + + + + + {{/properties}} +
NameValueDescription
{{.getKey()}}:
+
+
+
\ No newline at end of file diff --git a/hal-core/resources/web/room_config.tmpl b/hal-core/resources/web/room_config.tmpl new file mode 100644 index 00000000..9afde729 --- /dev/null +++ b/hal-core/resources/web/room_config.tmpl @@ -0,0 +1,86 @@ +

Room Configuration

+ +
+
+
Rooms
+
+

This is a list of all configured rooms.

+ + + + + + + + {{#rooms}} + + + + + + {{/rooms}} +
#Name + +
{{.getId()}}{{.getName()}} +
+ + +
+ + + +
+
+
+
+
+
+ + + + + + + diff --git a/resource/web/sensor_config.tmpl b/hal-core/resources/web/sensor_config.tmpl old mode 100755 new mode 100644 similarity index 71% rename from resource/web/sensor_config.tmpl rename to hal-core/resources/web/sensor_config.tmpl index 14e0aa1e..9af51b40 --- a/resource/web/sensor_config.tmpl +++ b/hal-core/resources/web/sensor_config.tmpl @@ -8,32 +8,34 @@ + {{#localSensors}} + + {{#detectedSensors}} @@ -71,8 +88,8 @@
# Name Type Public Configuration -
{{.getId()}} {{.getName()}} {{.getType()}} {{.isSynced()}} {{.getDeviceConfig()}}
- - +
- -
@@ -62,6 +64,21 @@
Date Data Configuration + +
+ + + +
+ +
{{.getDeviceConfig()}}
-
- + +
@@ -97,38 +115,39 @@ + {{#extUsers}} +
# Username Address Hostname Port -
{{.getUsername()}} {{.getAddress()}} {{.getHostname()}} {{.getPort()}}
- - +
- -
@@ -138,7 +157,7 @@ {{/extUsers}}
-
+
@@ -183,68 +202,16 @@ {{/extSensor}}
- + +
@@ -253,34 +220,41 @@